Iniciante 2.5 horas

Aula 2: Módulos e Sistema de Arquivos

Aprenda a trabalhar com módulos CommonJS e ES6, manipular arquivos e compreender o módulo fs

🎯 Objetivos da Aula

  • Trabalhar com módulos CommonJS e ES6
  • Manipular arquivos e diretórios
  • Compreender o módulo fs (File System)

🚀 Antes de Começar

📋 Pré-requisitos

  • Node.js instalado (Aula 1)
  • Editor de código (VS Code recomendado)
  • Terminal/Prompt de comando
  • Conhecimento básico de JavaScript

💡 Dicas Importantes

  • Pratique cada exemplo
  • Teste os códigos no seu computador
  • Não tenha medo de experimentar
  • Leia as mensagens de erro

🎯 O que você vai aprender hoje

Conceitos Fundamentais:

  • • O que são módulos e por que usar
  • • Como organizar código em arquivos
  • • Diferenças entre tipos de módulos

Habilidades Práticas:

  • • Criar e usar módulos próprios
  • • Ler e escrever arquivos
  • • Navegar entre pastas

🖥️ IMPORTANTE: Preparando seu Computador do Zero

⚠️ Leia Isto Primeiro!

Esta seção é para alunos que estão começando com um computador que SÓ TEM O VS CODE INSTALADO.

Se você já fez a Aula 1 e tem o Node.js funcionando, pode pular para a introdução.

📥 PASSO 1: Instalando o Node.js (Obrigatório!)

🌐 1.1 - Acessando o Site Oficial

O que fazer:

  1. Abra seu navegador (Chrome, Firefox, Edge...)
  2. Digite na barra de endereços: https://nodejs.org
  3. Pressione Enter

O que você vai ver:

  • Uma página com dois botões grandes de download
  • Um botão verde escrito "LTS" (Recommended for most users)
  • Um botão com "Current" (Latest features)

⬇️ 1.2 - Fazendo o Download

🎯 IMPORTANTE: Escolha sempre o LTS!

LTS significa "Long Term Support" (Suporte de Longo Prazo). É a versão mais estável e recomendada para aprender.

Passo a passo:

  1. Clique no botão verde "LTS" (não no Current!)
  2. O download vai começar automaticamente
  3. Aguarde o arquivo baixar (geralmente vai para a pasta Downloads)
  4. O arquivo terá um nome como: node-v20.x.x-x64.msi (Windows)

🔧 1.3 - Instalando o Node.js

Processo de instalação:

  1. Vá na pasta Downloads do seu computador
  2. Encontre o arquivo que você baixou (node-v20...)
  3. Clique duas vezes no arquivo para abrir o instalador
  4. Uma janela de instalação vai aparecer

Durante a instalação:

  1. Clique em "Next" (Próximo) em todas as telas
  2. Aceite os termos de licença (marque "I accept...")
  3. Mantenha o local de instalação padrão
  4. ⚠️ IMPORTANTE: Marque a opção "Add to PATH" (se aparecer)
  5. Clique em "Install" e aguarde
  6. Clique em "Finish" quando terminar

✅ PASSO 2: Verificando se Funcionou

🖥️ 2.1 - Abrindo o Terminal no VS Code

Como abrir o terminal:

  1. Abra o VS Code
  2. No menu superior, clique em "Terminal"
  3. Clique em "New Terminal" (Novo Terminal)
  4. Uma janela preta vai aparecer na parte de baixo do VS Code

💡 Atalho rápido:

Você também pode pressionar Ctrl + ` (Ctrl + crase) para abrir o terminal rapidamente!

🔍 2.2 - Testando o Node.js

Digite este comando no terminal:

node --version

Depois pressione Enter

✅ Se deu certo, você vai ver algo assim:

v20.11.0

(O número pode ser diferente, mas deve começar com "v")

❌ Se deu erro, você vai ver algo assim:

'node' is not recognized as an internal or external command

Se isso acontecer, vá para a seção "Problemas Comuns" no final desta aula!

📦 2.3 - Testando o NPM

O que é NPM?

NPM é como uma "loja de aplicativos" para programadores. Ele vem junto com o Node.js automaticamente!

Digite este comando no terminal:

npm --version

Depois pressione Enter

✅ Se deu certo, você vai ver algo assim:

10.2.4

(O número pode ser diferente)

📁 PASSO 3: Criando sua Pasta de Trabalho

🗂️ 3.1 - Criando a Pasta do Projeto

Onde criar a pasta:

  1. Abra o Explorador de Arquivos do Windows
  2. Vá para a pasta "Documentos" ou "Área de Trabalho"
  3. Clique com o botão direito em um espaço vazio
  4. Escolha "Novo" → "Pasta"
  5. Dê o nome: aula-2-nodejs

📂 3.2 - Abrindo a Pasta no VS Code

Como abrir no VS Code:

  1. Abra o VS Code
  2. Clique em "File" (Arquivo) no menu superior
  3. Clique em "Open Folder" (Abrir Pasta)
  4. Navegue até a pasta "aula-2-nodejs" que você criou
  5. Clique em "Select Folder" (Selecionar Pasta)

💡 Atalho rápido:

Você também pode pressionar Ctrl + K, Ctrl + O para abrir uma pasta rapidamente!

🎉 Parabéns! Seu Ambiente Está Pronto!

Se você chegou até aqui e todos os comandos funcionaram, seu computador está preparado para a aula!

Agora você pode continuar com a introdução da aula. Vamos aprender sobre módulos! 🚀

📦 PASSO EXTRA: Inicializando seu Projeto com NPM

🤔 O que é NPM e por que precisamos dele?

NPM significa "Node Package Manager" (Gerenciador de Pacotes do Node). É como uma "loja de aplicativos" para programadores!

Analogia: Imagine que você está montando um computador. Em vez de criar cada peça do zero, você compra peças prontas (processador, memória, etc.) e monta tudo junto. O NPM faz isso com código!

📋 O que é o package.json?

O package.json é como a "carteira de identidade" do seu projeto! Ele guarda informações importantes como:

  • Nome do projeto
  • Versão atual
  • Descrição do que o projeto faz
  • Lista de "peças" (bibliotecas) que o projeto usa
  • Comandos especiais para executar o projeto

🚀 PASSO A PASSO: Criando o package.json

1️⃣ Abra o Terminal no VS Code

Se o terminal não estiver aberto, pressione Ctrl + ' (aspas simples) ou vá no menu Terminal → New Terminal

2️⃣ Verifique se está na pasta correta

Digite este comando para ver onde você está:

PS C:\Users\SeuNome\meu-projeto> pwd

Resultado esperado: Deve mostrar o caminho da pasta do seu projeto

3️⃣ Execute o comando mágico do NPM

Digite exatamente este comando:

PS C:\Users\SeuNome\meu-projeto> npm init -y

🤓 Explicação do comando:

  • npm = chama o gerenciador de pacotes
  • init = inicializa um novo projeto
  • -y = responde "sim" para todas as perguntas automaticamente

4️⃣ Verifique o resultado

O que deve acontecer:

  • O comando vai executar rapidamente (1-2 segundos)
  • Vai aparecer uma mensagem de sucesso
  • Um arquivo chamado package.json será criado na sua pasta

5️⃣ Confira se deu certo

Olhe na barra lateral do VS Code. Você deve ver:

📁 meu-projeto/
    📄 package.json ← NOVO ARQUIVO!

👀 Vamos Espiar o package.json!

Clique no arquivo package.json na barra lateral para abri-lo. Você verá algo parecido com isto:

{
  "name": "meu-projeto",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

🎉 Perfeito! Este é o "RG" do seu projeto. Não se preocupe em entender tudo agora, vamos usar isso mais para frente!

🚨 Problemas Comuns e Soluções

❌ Erro: "npm não é reconhecido"

Causa: Node.js não foi instalado corretamente

Solução: Volte na seção anterior e reinstale o Node.js

❌ Erro: "Acesso negado" ou "Permission denied"

Causa: Pasta sem permissão de escrita

Solução: Crie a pasta em um local diferente (ex: Desktop)

❌ Comando não faz nada

Causa: Você não está na pasta correta

Solução: Use cd nome-da-pasta para entrar na pasta do projeto

✅ Checkpoint: Verifique se está tudo certo!

Antes de continuar, confirme que você tem:

  • ✅ Pasta do projeto criada
  • ✅ Pasta aberta no VS Code
  • ✅ Node.js funcionando (testado com node --version)
  • ✅ NPM funcionando (testado com npm --version)
  • ✅ Arquivo package.json criado na pasta

🎉 Tudo certo? Agora sim podemos começar a aprender sobre módulos!

1. Bem-vindo de volta! 👋

🎉 Parabéns por chegar até aqui!

Na Aula 1, você aprendeu o que é o Node.js, instalou ele no seu computador e criou seu primeiro programa! Lembra do famoso "Hello World"? 😊

Hoje vamos dar o próximo passo: aprender a organizar nosso código de forma inteligente usando módulos.

🤔 Mas o que são módulos mesmo?

Resposta simples: Módulos são como gavetas organizadas onde você guarda diferentes tipos de código!

Imagine sua mesa de estudos: você tem uma gaveta para canetas, outra para papéis, outra para calculadora... Módulos fazem a mesma coisa com seu código JavaScript! 📝

📱 Analogia: Módulos como Apps do seu Celular

Pense no seu celular: você não tem um único app gigante que faz tudo, né? Você tem vários apps pequenos, cada um com sua função específica! 📲

📷

App de Fotos

Módulo que cuida das imagens

💬

WhatsApp

Módulo que cuida das mensagens

🎵

Spotify

Módulo que cuida da música

💡 Sacou a ideia? Cada app tem sua responsabilidade, mas todos funcionam no mesmo celular. No Node.js é igual: cada módulo tem sua função, mas todos trabalham juntos no mesmo projeto!

✨ Por que usar módulos? (4 motivos simples!)

1. 📁 Organização (como arrumar seu quarto!)

Em vez de ter tudo bagunçado em um arquivo gigante, você separa cada coisa no seu lugar. Fica muito mais fácil de encontrar o que você precisa!

2. 🔄 Reutilização (não reinvente a roda!)

Criou uma função legal? Coloque em um módulo e use em vários projetos! É como ter uma receita de bolo que você pode fazer sempre que quiser.

3. 🛡️ Proteção (evita bagunça!)

Cada módulo fica "na sua", sem interferir nos outros. É como ter gavetas separadas - as coisas não se misturam!

4. 👥 Trabalho em equipe (cada um no seu quadrado!)

Quando você trabalha com outras pessoas, cada um pode cuidar de um módulo diferente. Ninguém atrapalha ninguém!

💡 Exemplo do Mundo Real

Pense no seu celular: você tem um app para fotos, outro para mensagens, outro para música. Cada app é como um módulo - tem sua função específica, mas todos trabalham juntos no mesmo sistema!

No Node.js, fazemos a mesma coisa: criamos "apps" (módulos) para diferentes funções do nosso projeto.

2. Sistema de Módulos do Node.js - Explicação Completa

📚 O que são Módulos?

Definição Simples: Módulos são arquivos JavaScript que contêm código específico e podem ser reutilizados em outros arquivos.

Analogia: É como ter uma caixa de ferramentas. Cada ferramenta (função) fica organizada e você pega apenas o que precisa para cada trabalho!

🗂️ Tipos de Módulos (Explicação Detalhada)

🏠 CASA

1. 🧰 Caixa de Ferramentas do Node.js (módulos nativos)

Imagina que quando você instala o Node.js, ele já vem com uma caixa de ferramentas cheia de coisas úteis! Você não precisa comprar nada extra, já está tudo lá esperando você usar.

🔧 Algumas ferramentas que já vêm na caixa:

📁 fs

Para mexer com arquivos (criar, ler, deletar)

🌐 http

Para criar sites e APIs

🗺️ path

Para trabalhar com endereços de arquivos

💻 os

Para saber informações do computador

💡 Dica: É como quando você compra um celular novo - ele já vem com apps básicos instalados (câmera, calculadora, etc.). O Node.js funciona igual!

🚀 PREPARAÇÃO COMPLETA - Do Zero ao Funcionando!

📋 REQUISITOS - O que você precisa ter:
  • ✅ VS Code instalado
  • ✅ Node.js instalado (baixe em nodejs.org se não tiver)
  • ✅ Um computador com Windows, Mac ou Linux
📁 PASSO 1: Criando a Pasta do Projeto
🖥️ Opção 1: Pelo Explorador de Arquivos
  1. Abra o Explorador de Arquivos (Windows) ou Finder (Mac)
  2. Navegue até a Área de Trabalho ou uma pasta de sua escolha
  3. Clique com botão direito → "Nova Pasta" ou "New Folder"
  4. Digite o nome: meu-logger-projeto
  5. Pressione Enter
⌨️ Opção 2: Pelo Terminal

# Navegue até onde quer criar (exemplo: Área de Trabalho)

cd Desktop

# Crie a pasta

mkdir meu-logger-projeto

# Entre na pasta

cd meu-logger-projeto

💻 PASSO 2: Abrindo no VS Code
🖱️ Método 1: Arrastar e Soltar
  1. Abra o VS Code
  2. Arraste a pasta meu-logger-projeto para dentro do VS Code
  3. A pasta vai aparecer no painel esquerdo
📂 Método 2: Abrir Pasta
  1. Abra o VS Code
  2. Vá em "File" → "Open Folder" (ou Ctrl+K, Ctrl+O)
  3. Navegue até a pasta meu-logger-projeto
  4. Clique em "Selecionar Pasta"
⌨️ Método 3: Terminal

# Dentro da pasta do projeto

code .

📝 PASSO 3: Criando o Arquivo logger.js
🆕 Como criar o arquivo:
  1. No VS Code, olhe o painel esquerdo (Explorer)
  2. Clique com botão direito na pasta do projeto
  3. Escolha "New File" ou "Novo Arquivo"
  4. Digite exatamente: logger.js
  5. Pressione Enter
  6. O arquivo vai abrir na tela principal
💾 Digite este código COMPLETO no logger.js:
// logger.js - Sistema de Logger para nossa aplicação
// Este arquivo cria uma "classe" que sabe como salvar mensagens em arquivos

// 1. IMPORTAÇÕES - Trazendo as ferramentas que vamos usar
const fs = require('fs').promises;  // Sistema de arquivos (jeito moderno que não trava)
const path = require('path');        // Manipulação de caminhos

// 2. CLASSE LOGGER - Nossa "fábrica" de logs
class Logger {
    // CONSTRUTOR - Executa quando criamos um novo Logger
    constructor(logFile = 'app.log') {
        // __dirname = pasta atual do arquivo
        // path.join = junta caminhos de forma segura
        this.logFile = path.join(__dirname, logFile);
        console.log(`📝 Logger criado! Arquivo: ${this.logFile}`);
    }
    
    // MÉTODO PRINCIPAL - Escreve qualquer tipo de log
    async log(message, level = 'INFO') {
        // Cria um "carimbo de data e hora" (tipo: 2024-01-15 às 10:30:45)
        const timestamp = new Date().toISOString(); // Pega a data/hora atual e transforma em texto
        
        // Monta a linha do log: [DATA] NÍVEL: MENSAGEM
        const logEntry = `[${timestamp}] ${level}: ${message}\n`;
        
        try {
            // appendFile = "cola" no final do arquivo (como escrever no final de um caderno)
            await fs.appendFile(this.logFile, logEntry);
            console.log(`✅ Log salvo: ${level} - ${message}`);
        } catch (error) {
            console.error('❌ Erro ao escrever log:', error.message);
        }
    }
    
    // MÉTODO DE CONVENIÊNCIA - Para logs informativos
    async info(message) {
        await this.log(message, 'INFO');
    }
    
    // MÉTODO DE CONVENIÊNCIA - Para logs de erro
    async error(message) {
        await this.log(message, 'ERROR');
    }
    
    // MÉTODO EXTRA - Para logs de aviso
    async warn(message) {
        await this.log(message, 'WARN');
    }
}

// EXPORTA a classe para outros arquivos usarem
module.exports = Logger;
💾 IMPORTANTE - Salve o arquivo!
  • Pressione Ctrl+S (Windows) ou Cmd+S (Mac)
  • Ou vá em "File" → "Save"
  • O ponto branco ao lado do nome do arquivo deve desaparecer
  • Se não salvar, o próximo passo não vai funcionar!

🧪 PASSO 4: Testando o Logger (CRIANDO O ARQUIVO DE TESTE):

PASSO 4.1: Crie o arquivo test-logger.js

📝 Como criar o arquivo:
  1. No VS Code, clique com botão direito na pasta (lado esquerdo)
  2. Escolha "Novo Arquivo" ou "New File"
  3. Digite exatamente: test-logger.js
  4. Pressione Enter
  5. O arquivo vai aparecer aberto na tela

Digite este código no arquivo test-logger.js:

// test-logger.js - Arquivo para testar nosso logger
// ATENÇÃO: Este arquivo deve estar na MESMA PASTA que o logger.js

// LINHA 1: Importa nossa classe Logger do arquivo logger.js
// O './' significa "na mesma pasta que este arquivo"
const Logger = require('./logger');

// LINHA 2: Função que vai testar nosso logger
// 'async' significa que esta função pode "esperar" outras operações
async function testarLogger() {
    console.log('🚀 Iniciando teste do Logger...');
    
    // LINHA 3: Cria um novo logger que vai salvar no arquivo 'teste.log'
    const logger = new Logger('teste.log');
    
    // LINHA 4: Testa diferentes tipos de mensagem
    // Cada linha vai aparecer no console E ser salva no arquivo
    // IMPORTANTE: Usamos 'await' para esperar cada operação terminar
    await logger.info('Aplicação iniciada com sucesso!');
    await logger.warn('Esta é uma mensagem de aviso');
    await logger.error('Simulando um erro de teste');
    
    console.log('✅ Teste concluído! Verifique o arquivo teste.log');
}

// LINHA 5: Executa nossa função de teste
testarLogger();

PASSO 4.2: Salve o arquivo

  • Pressione Ctrl+S (Windows) ou Cmd+S (Mac)
  • Ou vá em "Arquivo" → "Salvar"
  • O ponto branco ao lado do nome do arquivo deve desaparecer

PASSO 4.3: Execute no terminal

🖥️ Como abrir o terminal:
  • No VS Code: Menu "Terminal" → "Novo Terminal"
  • Ou use o atalho: Ctrl+Shift+` (acento grave)
  • Uma janela preta vai aparecer na parte de baixo

# Digite este comando e pressione Enter:

node test-logger.js

PASSO 4: Resultado esperado

🚀 Iniciando teste do Logger...

📝 Logger criado! Arquivo: C:\sua\pasta\teste.log

✅ Log salvo: INFO - Aplicação iniciada com sucesso!

✅ Log salvo: WARN - Esta é uma mensagem de aviso

✅ Log salvo: ERROR - Simulando um erro de teste

✅ Teste concluído! Verifique o arquivo teste.log

🎉 Se deu certo, você vai ver:
  • As mensagens no terminal (como mostrado acima)
  • Um novo arquivo chamado "teste.log" na sua pasta
  • Dentro do teste.log, as mensagens com data e hora
🔍 Por que usamos async/await?

Problema sem async/await: O código pode terminar antes de salvar todos os logs no arquivo.

Solução com async/await: Esperamos cada operação terminar antes de continuar.

💡 Analogia: É como esperar cada pessoa entrar no elevador antes de fechar a porta, em vez de fechar a porta enquanto alguém ainda está entrando!

🆘 Se der erro:
Erro: "Cannot find module './logger'"
  • Verifique se o arquivo logger.js existe na mesma pasta
  • Verifique se você salvou o arquivo logger.js
  • Verifique se o nome está correto (logger.js, não Logger.js)
Erro: "node não é reconhecido"
  • Node.js não está instalado ou não está no PATH
  • Reinstale o Node.js do site oficial
  • Reinicie o VS Code após a instalação
O código executa mas parece "incompleto":
  • Certifique-se de usar async function e await nas chamadas do logger
  • Sem await, o programa pode terminar antes de salvar todos os logs
  • Use o código corrigido mostrado acima
🔨 VOCÊ

2. 🛠️ Suas Próprias Ferramentas (módulos que você cria)

Às vezes você precisa de uma ferramenta específica que não existe na caixa do Node.js. Então você mesmo faz essa ferramenta! É como criar sua própria chave de fenda especial.

🎯 Exemplo prático: Você cria um arquivo calculadora.js com funções para somar, multiplicar, etc. Depois usa essas funções em outros arquivos do seu projeto.

💡 É como fazer uma receita de bolo e guardar numa pasta. Sempre que quiser fazer o bolo, você pega a receita e usa!

🌍 MUNDO

3. 🎁 Ferramentas de Outras Pessoas (módulos NPM)

Imagina uma loja gigante onde programadores do mundo todo deixam suas ferramentas de graça para você usar! Essa loja se chama NPM. Você "baixa" essas ferramentas com o comando npm install.

🎪 Algumas ferramentas famosas da "loja":

🚀 express

Para criar sites super rápido

🧩 lodash

Funções úteis para facilitar sua vida

🎨 colors

Para colorir texto no terminal

📅 moment

Para trabalhar com datas facilmente

💡 Dica: É como baixar apps no seu celular - você não precisa criar o WhatsApp, só baixa e usa!

🎯 PRÁTICA: Instalando e Usando seu Primeiro Pacote NPM

Vamos aprender na prática como "baixar" e usar uma ferramenta da "loja" NPM. Vamos usar o pacote colors para deixar nossos textos coloridos no terminal!

📦 PASSO 1: Instalando o Pacote
⌨️ No terminal do VS Code, digite:

# Instala o pacote 'colors' no seu projeto

npm install colors

O que cada parte significa:

  • npm = O "entregador" que busca pacotes na loja
  • install = "Instalar" ou "baixar"
  • colors = Nome do pacote que queremos
✅ O que você vai ver:

npm WARN deprecated colors@1.4.0: Please use...

added 1 package, and audited 2 packages in 2s

found 0 vulnerabilities

Não se preocupe com warnings! São só avisos, o pacote foi instalado com sucesso.

🔍 Verificando se instalou:
  • Apareceu uma pasta node_modules no seu projeto
  • O arquivo package.json agora tem uma seção "dependencies"
  • Apareceu um arquivo package-lock.json (é normal!)
📝 PASSO 2: Criando um Arquivo de Teste
🎨 Crie o arquivo: teste-cores.js

Clique com o botão direito na pasta do projeto → "Novo Arquivo" → digite "teste-cores.js"

💻 Digite este código:
// teste-cores.js - Testando o pacote 'colors'

// IMPORTA o pacote que acabamos de instalar
const colors = require('colors');

// FUNÇÃO PRINCIPAL - Testa diferentes cores
function testarCores() {
    console.log('🎨 Testando o pacote Colors!');
    console.log(''); // Linha em branco
    
    // Textos coloridos básicos
    console.log('Este texto é vermelho!'.red);
    console.log('Este texto é verde!'.green);
    console.log('Este texto é azul!'.blue);
    console.log('Este texto é amarelo!'.yellow);
    console.log('Este texto é magenta!'.magenta);
    console.log('Este texto é ciano!'.cyan);
    
    console.log(''); // Linha em branco
    
    // Textos com estilos
    console.log('Este texto está em negrito!'.bold);
    console.log('Este texto está sublinhado!'.underline);
    console.log('Este texto está invertido!'.inverse);
    
    console.log(''); // Linha em branco
    
    // Combinando cores e estilos
    console.log('Texto verde e negrito!'.green.bold);
    console.log('Texto azul e sublinhado!'.blue.underline);
    console.log('Texto vermelho invertido!'.red.inverse);
    
    console.log(''); // Linha em branco
    
    // Usando cores de fundo
    console.log('Texto com fundo vermelho'.bgRed);
    console.log('Texto com fundo verde'.bgGreen);
    console.log('Texto branco com fundo azul'.white.bgBlue);
    
    console.log(''); // Linha em branco
    console.log('🎉 Teste concluído! Seu terminal agora tem cores!'.rainbow);
}

// EXECUTA a função
testarCores();
🚀 PASSO 3: Executando o Teste
⌨️ No terminal, execute:

# Executa nosso arquivo de teste

node teste-cores.js

🌈 O que você deve ver:

🎨 Testando o pacote Colors!

Este texto é vermelho!

Este texto é verde!

Este texto é azul!

Este texto é amarelo!

Este texto é magenta!

Este texto é ciano!

Este texto está em negrito!

Este texto está sublinhado!

🎉 Teste concluído! Seu terminal agora tem cores!

Nota: No terminal real, as cores serão muito mais vibrantes!

🧠 ENTENDENDO O QUE ACONTECEU
🔍 Análise do código:

const colors = require('colors');

"Importa" o pacote colors para usar no nosso código

'texto'.red

O pacote "adiciona" métodos às strings para colorir

'texto'.green.bold

Você pode "encadear" estilos (verde + negrito)

node_modules/

Pasta onde ficam todos os pacotes instalados

🎯 Conceito importante: Quando você faz require('colors'), o Node.js automaticamente procura na pasta node_modules e encontra o pacote!

✅ CHECKPOINT: Você conseguiu?

Marque o que você conseguiu fazer:

  • □ Executei npm install colors sem erros
  • □ Apareceu a pasta node_modules no meu projeto
  • □ Criei o arquivo teste-cores.js
  • □ Executei node teste-cores.js
  • □ Vi textos coloridos no terminal
  • □ Entendi como o require('colors') funciona

🎉 Se você marcou todos os itens, parabéns! Você acabou de usar seu primeiro pacote NPM externo!

📦 PASSO EXTRA: Inicializando um Projeto Node.js Profissional

🤔 Por que precisamos do npm init?

Imagine que você está organizando uma festa. Você precisa de uma lista com:

  • 📋 Nome da festa
  • 👥 Quem organizou
  • 🎂 Que tipo de festa é
  • 🛍️ Lista de coisas que você vai precisar comprar

O package.json é exatamente isso para seu projeto! É um arquivo que diz:

  • 📋 Nome do projeto
  • 👨‍💻 Quem criou
  • 🎯 Que tipo de projeto é
  • 📦 Lista de "ingredientes" (bibliotecas) que o projeto precisa
⚡ PASSO 1: Abra o Terminal no VS Code
🖥️ Como abrir:
  • No VS Code: Menu "Terminal" → "Novo Terminal"
  • Ou use o atalho: Ctrl+Shift+` (acento grave)
  • Uma janela preta vai aparecer na parte de baixo
  • Certifique-se de que está na pasta do seu projeto

💡 Dica: O terminal deve mostrar o caminho da sua pasta do projeto. Se não estiver, navegue até ela com cd caminho/para/sua/pasta

🚀 PASSO 2: Execute o npm init
⌨️ Digite este comando:

# O comando mágico que cria o package.json

npm init -y

O que significa cada parte:

  • npm = O "assistente" que gerencia pacotes
  • init = "Inicializar" um novo projeto
  • -y = "Yes" para tudo (aceita as configurações padrão)
✅ O que você vai ver:

Wrote to C:\sua\pasta\package.json:

{

"name": "meu-logger-projeto",

"version": "1.0.0",

"description": "",

"main": "index.js",

"scripts": {

"test": "echo \"Error: no test specified\" && exit 1"

},

"keywords": [],

"author": "",

"license": "ISC"

}

📋 PASSO 3: Entendendo o package.json
🔍 Vamos "traduzir" cada linha:

"name": Nome do seu projeto (como o nome da festa)

Vai ser o nome da pasta por padrão

"version": Versão do seu projeto (como "versão 1.0")

Começa sempre com 1.0.0

"description": Descrição do que o projeto faz

Está vazio, você pode preencher depois

"main": Arquivo principal do projeto

Por padrão é "index.js" (você pode mudar)

"scripts": Comandos que você pode executar

Como atalhos para tarefas comuns

"author": Quem criou o projeto (você!)

Pode adicionar seu nome depois

🎯 PASSO 4: Verificando se deu certo
✅ Checklist de verificação:
  • Apareceu um arquivo package.json na sua pasta (lado esquerdo do VS Code)
  • O terminal mostrou a mensagem "Wrote to..." com o conteúdo do arquivo
  • Você pode abrir o arquivo package.json e ver o conteúdo
  • Não apareceu nenhuma mensagem de erro vermelha

🎉 Parabéns! Agora seu projeto está "oficialmente" configurado como um projeto Node.js. É como se você tivesse criado a "certidão de nascimento" do seu projeto!

🆘 Se algo der errado:
Erro: "npm não é reconhecido"
  • Node.js não foi instalado corretamente
  • Reinstale o Node.js do site oficial (nodejs.org)
  • Reinicie o VS Code após a instalação
  • Teste com node --version e npm --version
Erro: "permission denied" ou "acesso negado"
  • Execute o VS Code como administrador
  • Ou mude para uma pasta onde você tem permissão (como Desktop)
O arquivo package.json não apareceu:
  • Verifique se você está na pasta correta do projeto
  • Atualize a visualização do VS Code (F5)
  • Tente executar o comando novamente

👨‍💻 Vamos Criar Nosso Primeiro Módulo!

📂 Onde fazer isso?

  1. 1. Abra o terminal/prompt de comando
  2. 2. Navegue até uma pasta onde você quer criar o projeto
  3. 3. Crie uma nova pasta: mkdir meu-primeiro-modulo
  4. 4. Entre na pasta: cd meu-primeiro-modulo
  5. 5. Abra o VS Code: code .

📝 Passo 1: Criando o arquivo math.js

No VS Code: Clique com o botão direito na área de arquivos → "New File" → Digite "math.js"

// math.js - Módulo de operações matemáticas
// Este arquivo contém funções para cálculos básicos

// Função para somar dois números
function somar(a, b) {
    console.log(`Somando ${a} + ${b}`);
    return a + b;  // Retorna o resultado da soma
}

// Função para multiplicar dois números
function multiplicar(a, b) {
    console.log(`Multiplicando ${a} × ${b}`);
    return a * b;  // Retorna o resultado da multiplicação
}

// Função para dividir dois números
function dividir(a, b) {
    if (b === 0) {
        console.log('Erro: Não é possível dividir por zero!');
        return null;
    }
    console.log(`Dividindo ${a} ÷ ${b}`);
    return a / b;
}

// IMPORTANTE: Exportando as funções para outros arquivos poderem usar
// É como "emprestar" suas ferramentas para outros arquivos
module.exports = {
    somar,
    multiplicar,
    dividir
};

// Explicação do module.exports:
// - É a forma de "disponibilizar" suas funções para outros arquivos
// - Sem isso, outros arquivos não conseguem usar suas funções
// - É como colocar suas ferramentas numa caixa para emprestar

📝 Passo 2: Criando o arquivo principal (app.js)

No VS Code: Crie outro arquivo chamado "app.js" (este será nosso arquivo principal)

// app.js - Arquivo principal que usa o módulo math.js
// Este arquivo vai "importar" e usar as funções do math.js

// IMPORTANDO o módulo que criamos
// O './' significa "na mesma pasta"
const math = require('./math.js');

// Agora podemos usar as funções do módulo math!
console.log('=== TESTANDO NOSSO MÓDULO MATEMÁTICO ===');

// Testando a função somar
const resultadoSoma = math.somar(10, 5);
console.log('Resultado da soma:', resultadoSoma);

// Testando a função multiplicar
const resultadoMultiplicacao = math.multiplicar(4, 7);
console.log('Resultado da multiplicação:', resultadoMultiplicacao);

// Testando a função dividir
const resultadoDivisao = math.dividir(20, 4);
console.log('Resultado da divisão:', resultadoDivisao);

// Testando divisão por zero (para ver o tratamento de erro)
const divisaoPorZero = math.dividir(10, 0);
console.log('Divisão por zero:', divisaoPorZero);

console.log('=== TESTE CONCLUÍDO ===');

🚀 Passo 3: Executando o código

💻 Como executar:

  1. 1. Abra o terminal no VS Code (Terminal → New Terminal)
  2. 2. Certifique-se de estar na pasta do projeto (meu-primeiro-modulo)
  3. 3. Digite o comando: node app.js
  4. 4. Pressione Enter e veja a mágica acontecer!

📋 Resultado Esperado

$ node app.js
=== TESTANDO NOSSO MÓDULO MATEMÁTICO ===
Somando 10 + 5
Resultado da soma: 15
Multiplicando 4 × 7
Resultado da multiplicação: 28
Dividindo 20 ÷ 4
Resultado da divisão: 5
Erro: Não é possível dividir por zero!
Divisão por zero: null
=== TESTE CONCLUÍDO ===

🎉 Parabéns!

Você acabou de criar e usar seu primeiro módulo Node.js! Agora você entende como:

  • ✅ Criar funções em um arquivo separado
  • ✅ Exportar funções usando module.exports
  • ✅ Importar e usar funções em outro arquivo
  • ✅ Organizar seu código de forma modular

🔧 Troubleshooting (Problemas Comuns)

❌ Erro: "Cannot find module './math.js'"

Causa: O arquivo math.js não existe ou está em outra pasta

Solução: Verifique se o arquivo math.js está na mesma pasta que app.js

❌ Erro: "math.somar is not a function"

Causa: A função não foi exportada corretamente

Solução: Verifique se você colocou a função dentro do module.exports

❌ Nada acontece quando executo

Causa: Você pode estar na pasta errada

Solução: Use ls (Mac/Linux) ou dir (Windows) para ver se os arquivos estão na pasta atual

multiplicar }; // app.js - Usando o módulo const math = require('./math'); console.log(math.somar(5, 3)); // 8 console.log(math.multiplicar(4, 2)); // 8

3. CommonJS vs ES6 Modules - Duas Formas de Organizar Código

💡 Analogia: Duas Formas de Emprestar Livros

Imagine que você tem uma biblioteca pessoal e quer emprestar livros para amigos:

  • CommonJS: Como uma biblioteca tradicional - você pede um livro específico e recebe ele completo
  • ES6 Modules: Como uma biblioteca moderna - você pode pedir capítulos específicos ou o livro todo

🤔 Por que Existem Duas Formas?

CommonJS foi criado especificamente para o Node.js quando JavaScript ainda não tinha um sistema oficial de módulos. É como o "jeito antigo" que funciona muito bem.

ES6 Modules é o sistema "oficial" que veio depois, criado pelos criadores do JavaScript. É mais moderno e será o padrão do futuro.

📦 CommonJS (require/module.exports)

O jeito "tradicional" do Node.js - como uma "lojinha" que vende e compra coisas

🏪 Analogia da Lojinha:

module.exports = "Prateleira da loja" (o que você está vendendo)

require = "Ir comprar" na loja de outro arquivo

É como se cada arquivo fosse uma lojinha que pode vender suas funções para outros arquivos!

Como Exportar (pessoa.js):

// pessoa.js - Criando nosso "produto" para vender

// Jeito 1: Exportar um objeto completo
module.exports = {
    nome: 'João',
    idade: 30,
    falar: function() {
        return `Olá, eu sou ${this.nome}`;
    }
};

// Jeito 2: Exportar uma função
// module.exports = function(nome) {
//     return `Olá, ${nome}!`;
// };

Como Importar (app.js):

// app.js - "Comprando" o que a pessoa.js está vendendo

// Importar tudo que pessoa.js exporta
const pessoa = require('./pessoa');

// Agora posso usar:
console.log(pessoa.nome);     // João
console.log(pessoa.idade);    // 30
console.log(pessoa.falar());  // Olá, eu sou João
Características:
  • ✅ Padrão do Node.js (funciona sempre)
  • ✅ Carregamento síncrono (espera carregar)
  • ✅ Dinâmico (pode importar condicionalmente)
  • ✅ Mais simples para iniciantes

🚀 ES6 Modules (import/export)

O jeito "moderno" do JavaScript - como um "supermercado" mais organizado

🛒 Analogia do Supermercado:

export = "Colocar produtos nas prateleiras" (organizados por seção)

import = "Pegar só o que precisa" do carrinho

É mais organizado que a lojinha - você pode pegar só os itens específicos que quer!

Como Exportar (pessoa.js):

// pessoa.js - Como um "supermercado" vendendo itens organizados

// JEITO 1: Exportar itens individuais (como colocar produtos em prateleiras separadas)
export const nome = 'João';
export const idade = 30;
export function falar() {
    return `Olá, eu sou ${nome}`;
}

// JEITO 2: Exportar um item "principal" (default) - como o "produto em destaque"
export default {
    nome: 'João',
    idade: 30,
    falar() {
        return `Olá, eu sou ${this.nome}`;
    }
};

Como Importar (app.js):

// app.js - "Fazendo compras" no supermercado

// OPÇÃO 1: Importar itens específicos (como pegar só pão e leite)
import { nome, idade, falar } from './pessoa.js';
console.log(nome);    // João
console.log(falar()); // Olá, eu sou João

// OPÇÃO 2: Importar o item principal (como pegar o "produto em destaque")
import pessoa from './pessoa.js';
console.log(pessoa.nome);     // João
console.log(pessoa.falar());  // Olá, eu sou João

// OPÇÃO 3: Importar tudo (como levar o carrinho inteiro)
import * as todasAsCoisas from './pessoa.js';
console.log(todasAsCoisas.nome); // João
Características:
  • ✅ Padrão oficial do JavaScript
  • ✅ Mais flexível (importa só o que precisa)
  • ✅ Melhor para performance
  • ⚠️ Precisa configurar no Node.js

⚙️ Como Usar ES6 Modules no Node.js (Passo a Passo)

Por padrão, o Node.js fala "CommonJS" (a linguagem da lojinha). Para usar ES6 modules (linguagem do supermercado), você precisa "ensinar" uma nova linguagem ao Node.js!

🗣️ Analogia da Linguagem:

É como se o Node.js só soubesse falar "português" (CommonJS). Para ele entender "inglês" (ES6), você precisa dar um "dicionário" para ele!

📝 Método 1: Usando package.json (Mais Fácil! 👍)

É como dar um "manual de instruções" para o Node.js!

  1. PASSO 1: Crie um arquivo package.json na pasta do projeto:
{
  "name": "meu-projeto-es6",
  "version": "1.0.0",
  "type": "module",
  "description": "Projeto usando ES6 modules"
}

🔑 A Linha Mágica: "type": "module" é como dizer ao Node.js: "Oi Node.js! A partir de agora, fale a linguagem do supermercado (ES6), não da lojinha!"

📝 Método 2: Usando extensão .mjs (Alternativo)

É como colocar uma "etiqueta especial" nos arquivos para o Node.js saber que são "supermercado":

Renomeie seus arquivos de .js para .mjs:

  • pessoa.jspessoa.mjs
  • app.jsapp.mjs

👍 Vantagem: Não precisa criar o "manual" (package.json)
👎 Desvantagem: Extensão diferente pode confundir (como ter dois tipos de arquivo)

🧪 Exemplo Prático: Testando a Opção 2 (.mjs)

Vamos criar um exemplo usando a extensão .mjs:

Passo 1: Crie uma pasta e os arquivos iniciais:

# Crie e entre na pasta

mkdir teste-mjs

cd teste-mjs

code .

Passo 2: Crie o arquivo pessoa.js (com código ES6):

// pessoa.js - Arquivo inicial com ES6
export function criarPessoa(nome, idade) {
    return {
        nome: nome,
        idade: idade,
        apresentar() {
            return `Olá, eu sou ${this.nome} e tenho ${this.idade} anos!`;
        }
    };
}

export const saudacao = "Bem-vindo ao ES6 modules!";

Passo 3: Crie o arquivo app.js (que usa pessoa.js):

// app.js - Arquivo que importa pessoa.js
import { criarPessoa, saudacao } from './pessoa.js';

console.log(saudacao);

const pessoa1 = criarPessoa('Maria', 25);
const pessoa2 = criarPessoa('João', 30);

console.log(pessoa1.apresentar());
console.log(pessoa2.apresentar());

Passo 4: Agora renomeie os arquivos para .mjs:

# No Windows (PowerShell ou CMD):

ren pessoa.js pessoa.mjs

ren app.js app.mjs

# No Linux/Mac:

mv pessoa.js pessoa.mjs

mv app.js app.mjs

Passo 5: Atualize o import no app.mjs:

// app.mjs - Atualize a linha de import
import { criarPessoa, saudacao } from './pessoa.mjs'; // ← Mudou para .mjs

console.log(saudacao);

const pessoa1 = criarPessoa('Maria', 25);
const pessoa2 = criarPessoa('João', 30);

console.log(pessoa1.apresentar());
console.log(pessoa2.apresentar());

Passo 6: Execute o arquivo .mjs:

node app.mjs

✅ Resultado Esperado:
Bem-vindo ao ES6 modules!
Olá, eu sou Maria e tenho 25 anos!
Olá, eu sou João e tenho 30 anos!

🧪 Exemplo Prático: Testando a Opção 1 (package.json)

Agora vamos ver como fazer com package.json:

# Crie e entre na pasta

mkdir teste-es6-modules

cd teste-es6-modules

# Abra no VS Code

code .

Passo 2: Crie o arquivo package.json:

{
  "name": "teste-es6-modules",
  "version": "1.0.0",
  "type": "module",
  "description": "Testando ES6 modules"
}

Passo 3: Crie o arquivo utils.js (com ES6 export):

// utils.js - Funções utilitárias usando ES6 modules

// Exportando funções individuais (named exports)
export function cumprimentar(nome) {
    return `Olá, ${nome}! Bem-vindo ao ES6 modules!`;
}

export function calcularIdade(anoNascimento) {
    const anoAtual = new Date().getFullYear();
    return anoAtual - anoNascimento;
}

export const PI = 3.14159;

// Exportando uma função como padrão (default export)
export default function despedir(nome) {
    return `Tchau, ${nome}! Até a próxima!`;
}

Passo 4: Crie o arquivo app.js (com ES6 import):

// app.js - Usando ES6 imports

// Importando funções específicas (named imports)
import { cumprimentar, calcularIdade, PI } from './utils.js';

// Importando a função padrão (default import)
import despedir from './utils.js';

// Testando as funções
console.log('=== TESTANDO ES6 MODULES ===');

// Usando named imports
console.log(cumprimentar('Maria'));
console.log('Idade:', calcularIdade(1990));
console.log('Valor de PI:', PI);

// Usando default import
console.log(despedir('Maria'));

console.log('=== TESTE CONCLUÍDO ===');

Passo 5: Execute o teste:

node app.js

✅ Resultado Esperado:

=== TESTANDO ES6 MODULES ===
Olá, Maria! Bem-vindo ao ES6 modules!
Idade: 34
Valor de PI: 3.14159
Tchau, Maria! Até a próxima!
=== TESTE CONCLUÍDO ===
Por padrão, o Node.js usa CommonJS. Para usar ES6 modules, você precisa "avisar" o Node.js:

Opção 1: Modificar package.json (Recomendado)

{
  "name": "meu-projeto",
  "version": "1.0.0",
  "type": "module",  ← Adicione esta linha
  "main": "app.js"
}

Agora TODOS os arquivos .js usarão ES6 modules

Opção 2: Usar extensão .mjs (Alternativa)

📝 IMPORTANTE: Primeiro você precisa criar os arquivos com código ES6, depois renomeá-los!

Passo a passo:

  1. 1. Crie os arquivos normais (.js) com código ES6
  2. 2. Depois renomeie para extensão .mjs
  3. 3. Execute com node arquivo.mjs
# Exemplo: depois de criar os arquivos, renomeie:
pessoa.js → pessoa.mjs
app.js → app.mjs

# Execute assim:
node app.mjs

Apenas arquivos .mjs usarão ES6 modules (sem precisar do package.json)

📋 Resumo: Como Usar ES6 Modules

✅ Opção 1: package.json (Mais Fácil)
  1. 1. Crie pasta do projeto
  2. 2. Crie package.json com "type": "module"
  3. 3. Crie arquivos .js com código ES6
  4. 4. Execute: node arquivo.js
⚡ Opção 2: extensão .mjs
  1. 1. Crie pasta do projeto
  2. 2. Crie arquivos .js com código ES6
  3. 3. Renomeie para .mjs
  4. 4. Atualize imports (.mjs)
  5. 5. Execute: node arquivo.mjs

💡 Dica Principal: SEMPRE crie os arquivos primeiro, depois configure! Não importa qual opção você escolher, você sempre precisa:

  • Criar uma pasta para organizar o projeto
  • Criar os arquivos .js com o código ES6 (import/export)
  • Depois escolher uma das duas opções de configuração

🛠️ Vamos Praticar: Criando um Módulo de Calculadora

📁 Passo 0: Preparando o Projeto (IMPORTANTE!)

Antes de criar os arquivos, vamos organizar nosso projeto:

1. Crie uma pasta para o projeto:
mkdir calculadora-projeto
cd calculadora-projeto
2. Abra a pasta no VS Code:
code .
3. Inicialize o projeto Node.js:
npm init -y

✅ Isso cria o arquivo package.json automaticamente!

💡 Por que fazer isso? O Node.js usa CommonJS por padrão, então nosso código com require() e module.exports funcionará perfeitamente!

Passo 1: Crie o arquivo calculadora.js

No seu editor de código, crie um novo arquivo chamado calculadora.js:

// calculadora.js - Versão CommonJS

// Função para somar dois números
function somar(a, b) {
    return a + b;  // Retorna a soma de a + b
}

// Função para subtrair dois números
function subtrair(a, b) {
    return a - b;  // Retorna a subtração de a - b
}

// Função para multiplicar dois números
function multiplicar(a, b) {
    return a * b;  // Retorna a multiplicação de a * b
}

// Função para dividir dois números
function dividir(a, b) {
    if (b === 0) {
        return 'Erro: Divisão por zero!';  // Evita erro matemático
    }
    return a / b;  // Retorna a divisão de a / b
}

// Exportar todas as funções para outros arquivos poderem usar
module.exports = {
    somar,        // Mesma coisa que somar: somar
    subtrair,     // Mesma coisa que subtrair: subtrair
    multiplicar,  // Mesma coisa que multiplicar: multiplicar
    dividir       // Mesma coisa que dividir: dividir
};

Passo 2: Crie o arquivo teste-calculadora.js

Agora crie outro arquivo para testar nossa calculadora:

// teste-calculadora.js - Testando nossa calculadora

// Importar todas as funções da calculadora
const calc = require('./calculadora');

// Testar cada função
console.log('=== TESTANDO NOSSA CALCULADORA ===');
console.log('');

// Teste da soma
console.log('Soma:');
console.log('5 + 3 =', calc.somar(5, 3));           // Resultado: 8
console.log('10 + 7 =', calc.somar(10, 7));         // Resultado: 17
console.log('');

// Teste da subtração
console.log('Subtração:');
console.log('10 - 4 =', calc.subtrair(10, 4));      // Resultado: 6
console.log('15 - 8 =', calc.subtrair(15, 8));      // Resultado: 7
console.log('');

// Teste da multiplicação
console.log('Multiplicação:');
console.log('4 × 3 =', calc.multiplicar(4, 3));     // Resultado: 12
console.log('7 × 6 =', calc.multiplicar(7, 6));     // Resultado: 42
console.log('');

// Teste da divisão
console.log('Divisão:');
console.log('15 ÷ 3 =', calc.dividir(15, 3));       // Resultado: 5
console.log('10 ÷ 2 =', calc.dividir(10, 2));       // Resultado: 5
console.log('10 ÷ 0 =', calc.dividir(10, 0));       // Resultado: Erro!
console.log('');

console.log('=== TESTE CONCLUÍDO ===');

Passo 3: Execute o teste

No terminal, navegue até a pasta do projeto e execute:

node teste-calculadora.js
Resultado Esperado:
=== TESTANDO NOSSA CALCULADORA ===

Soma:
5 + 3 = 8
10 + 7 = 17

Subtração:
10 - 4 = 6
15 - 8 = 7

Multiplicação:
4 × 3 = 12
7 × 6 = 42

Divisão:
15 ÷ 3 = 5
10 ÷ 2 = 5
10 ÷ 0 = Erro: Divisão por zero!

=== TESTE CONCLUÍDO ===

🤷‍♂️ Qual Devo Usar?

Use CommonJS quando:

  • ✅ Você está começando a aprender
  • ✅ Quer algo que "simplesmente funciona"
  • ✅ Está trabalhando com código legado
  • ✅ Não quer configurar nada extra

Use ES6 Modules quando:

  • ✅ Quer usar o padrão moderno
  • ✅ Precisa de melhor performance
  • ✅ Quer importar apenas partes específicas
  • ✅ Está criando um projeto novo

💡 Dica para Iniciantes: Comece com CommonJS (require/module.exports) porque é mais simples. Quando se sentir confortável, experimente ES6 Modules!

🚀 OPCIONAL: Convertendo para ES6 Modules (Avançado)

Se você quiser experimentar a sintaxe moderna, aqui está como converter nosso exercício:

📝 Passo Extra: Configurar ES6 Modules

Edite o arquivo package.json e adicione esta linha:

{
  "name": "calculadora-projeto",
  "version": "1.0.0",
  "type": "module",  ← Adicione esta linha!
  "main": "index.js",
  // ... resto do arquivo
}

🔄 calculadora.js (versão ES6):

// calculadora.js - Versão ES6 Modules

// Funções da calculadora (iguais!)
function somar(a, b) {
    return a + b;
}

function subtrair(a, b) {
    return a - b;
}

function multiplicar(a, b) {
    return a * b;
}

function dividir(a, b) {
    if (b === 0) {
        return 'Erro: Divisão por zero!';
    }
    return a / b;
}

// MUDANÇA: export em vez de module.exports
export {
    somar,
    subtrair,
    multiplicar,
    dividir
};

🔄 teste-calculadora.js (versão ES6):

// teste-calculadora.js - Versão ES6 Modules

// MUDANÇA: import em vez de require
import * as calc from './calculadora.js';

// O resto do código fica igual!
console.log('=== TESTANDO NOSSA CALCULADORA ===');
console.log('');

console.log('Soma:');
console.log('5 + 3 =', calc.somar(5, 3));
console.log('10 + 7 =', calc.somar(10, 7));
// ... resto igual ao exemplo anterior
⚠️ Diferenças importantes:
  • • Precisa adicionar "type": "module" no package.json
  • • Use import em vez de require()
  • • Use export em vez de module.exports
  • • Precisa incluir .js no final dos imports

4. 📁 Mexendo com Arquivos no Computador (módulo fs)

🔗 Lembra da aula 1?

Na aula 1, você aprendeu a fazer o Node.js mostrar coisas na tela com console.log(). Agora vamos aprender a fazer ele mexer com arquivos do seu computador! 🎉

💡 Pense assim: Antes você só sabia "falar" com o Node.js. Agora vai aprender a pedir para ele "pegar" e "guardar" coisas!

🤖 Node.js = Seu Robô Pessoal para Arquivos

Imagina que você tem um robô super obediente que pode fazer estas coisas:

📖 Ler arquivos

"Robô, me conta o que está escrito naquele arquivo!"

✍️ Escrever arquivos

"Robô, escreve isso num arquivo novo!"

🔍 Procurar arquivos

"Robô, esse arquivo existe?"

📁 Criar pastas

"Robô, organiza isso numa pasta nova!"

🎯 O que é esse tal de "fs"?

fs significa "File System" (Sistema de Arquivos). É como se fosse o "manual de instruções" para o seu robô Node.js mexer com arquivos! 🤖📚

🧠 Lembra: Na aula 1 você usou console.log() para mostrar coisas na tela. Agora vai usar fs para mexer com arquivos. É só mais uma ferramenta!

🤔 Duas maneiras de pedir coisas para o robô

🕐 Imagina que você tem um robô ajudante...

Quando você pede para o robô Node.js ler um arquivo, existem duas maneiras:

🛑 Jeito 1: "Espera aí!" (Síncrono)

Você fala: "Robô, vai buscar aquele arquivo!" e você fica parado esperando ele voltar. Não faz mais nada até ele trazer o arquivo.

⚠️ Problema: Se o arquivo for muito grande, você fica "travado" esperando!

✅ Jeito 2: "Vai lá, eu espero!" (Assíncrono)

Você fala: "Robô, vai buscar aquele arquivo e me avisa quando trouxer!" Enquanto isso, você continua fazendo outras coisas.

✨ Vantagem: Você não fica "travado" e pode fazer várias coisas ao mesmo tempo!

🏃‍♂️ Jeito 2: "Vai lá, eu espero!" (Assíncrono)

Você fala: "Robô, vai buscar aquele arquivo!" e você continua fazendo outras coisas. Quando ele trouxer, ele te avisa.

🧠 Resumindo: É como a diferença entre ficar parado esperando o elevador VS apertar o botão e ir fazer outras coisas até ele chegar!

🛑

Jeito 1: "Espera aí!" (Síncrono)

O programa para tudo e espera terminar de ler o arquivo

📝 Exemplo super simples:
// 1. Chama o robô fs
const fs = require('fs');

// 2. Fala para o usuário o que vai fazer
console.log('🤖 Vou ler o arquivo agora...');

// 3. PARA TUDO e espera ler o arquivo
const texto = fs.readFileSync('meuarquivo.txt', 'utf8');

// 4. Só executa DEPOIS de ler o arquivo
console.log('📄 Li o arquivo:', texto);
console.log('✅ Pronto!');
🎯 Quando usar este jeito:
  • ✅ Quando você está aprendendo (mais fácil)
  • ✅ Scripts pequenos e rápidos
  • ✅ Quando PRECISA do arquivo antes de continuar
  • ❌ Não use em sites (deixa tudo lento)
🏃‍♂️

Jeito 2: "Vai lá, eu espero!" (Assíncrono)

O programa continua fazendo outras coisas enquanto lê o arquivo

📝 Exemplo super simples:
// 1. Chama o robô fs
const fs = require('fs');

// 2. Fala para o usuário o que vai fazer
console.log('🤖 Vou PEDIR para ler o arquivo...');

// 3. Pede para ler, mas NÃO espera!
fs.readFile('meuarquivo.txt', 'utf8', (erro, texto) => {
    // Esta parte só roda QUANDO o arquivo for lido
    console.log('📄 Arquivo lido:', texto);
});

// 4. Esta linha roda IMEDIATAMENTE (não espera!)
console.log('🏃‍♂️ Continuei fazendo outras coisas!');

// Resultado: linha 2 → linha 4 → linha 3
🎯 Quando usar este jeito:
  • ✅ Sites e aplicações web
  • ✅ Quando quer que o programa seja rápido
  • ✅ Quando pode fazer outras coisas enquanto espera
  • ⚠️ Um pouco mais difícil de entender no início

🍕 Jeito 3: "Como pedir pizza pelo app!" (async/await)

É rápido como o Jeito 2, mas fácil de entender como o Jeito 1!

📱➡️🍕

🍕 Analogia da Pizza (palavras mágicas):

  • async = "Ei, vou fazer algo que demora!" (abre o app da pizzaria)
  • await = "Agora vou esperar!" (aguarda a pizza chegar)
  • • Enquanto espera, pode usar o celular para outras coisas!
  • • Quando a pizza chega, você para o que está fazendo para receber
  • Resumo: São palavrinhas especiais que fazem o código esperar na hora certa!
📝 Exemplo da pizza (código):
// 🍕 PASSO 1: Chama o "app da pizzaria" (versão moderna do fs)
const fs = require('fs').promises;  // Jeito moderno de mexer com arquivos

// 🍕 PASSO 2: Cria uma função especial para "pedir pizza" (async)
async function lerMeuArquivo() {
    console.log('📱 Abrindo o app para pedir pizza (ler arquivo)...');
    
    // 🍕 PASSO 3: "Aguarda" a pizza chegar (await)
    const texto = await fs.readFile('meuarquivo.txt', 'utf8');
    
    console.log('🍕 Pizza chegou! (arquivo lido):', texto);
    console.log('😋 Vou comer! (terminei)');
}

// 🍕 PASSO 4: Faz o pedido da pizza
lerMeuArquivo();
console.log('📱 Enquanto isso, vou mexer no celular!');

// 📱➡️🍕 Resultado: abrir app → mexer no celular → pizza chega → comer
🎯 Por que este jeito é o melhor:
  • Fácil de ler: Parece o Jeito 1 (linha por linha)
  • Rápido: Como o Jeito 2 (não trava)
  • Moderno: É como os programadores profissionais fazem hoje
  • Organizado: Seu código fica mais limpo
  • 💡 Dica: Comece com os Jeitos 1 e 2, depois venha para este!

🛠️ Principais Operações com Arquivos

📖 1. Lendo um Arquivo

Como fazer o Node.js "abrir" e "ler" um arquivo de texto

📝 Passo 1: Crie um arquivo para testar

Primeiro, vamos criar um arquivo de texto para o robô ler:

🖱️ Como fazer (passo a passo):

  1. 1. Clique com o botão direito na pasta do seu projeto
  2. 2. Escolha "Novo" → "Documento de Texto"
  3. 3. Renomeie para dados.txt
  4. 4. Abra o arquivo e digite o texto abaixo:

📄 Conteúdo do arquivo dados.txt:

Olá! Este é um arquivo de teste.
Esta é a segunda linha.
E esta é a terceira linha!

⚠️ Importante: O arquivo dados.txt deve estar na MESMA pasta que o seu código JavaScript!

Passo 2: Código para ler o arquivo (como um robô leitor)
// 📁 ler-arquivo.js
// 🤖 PASSO 1: Chama o robô que sabe ler arquivos
const fs = require('fs').promises;  // .promises = jeito moderno (como pedir pizza pelo app)

// 🤖 PASSO 2: Ensina o robô como ler arquivos
async function lerMeuArquivo() {
    try {
        console.log('🤖 Robô: "Vou tentar ler o arquivo arquivo-criado.txt..."');
        
        // 📖 PASSO 3: Robô lê o arquivo (utf8 = "leia como texto normal")
        const conteudo = await fs.readFile('arquivo-criado.txt', 'utf8');
        
        console.log('✅ Robô: "Consegui ler! Aqui está:"');
        console.log('📄 Conteúdo que o robô encontrou:');
        console.log('─'.repeat(40));
        console.log(conteudo);
        console.log('─'.repeat(40));
        
    } catch (error) {
        console.error(`❌ Robô: "Ops! Deu problema:"`, error.message);
        
        // 🆘 Robô explica o que pode ter dado errado
        if (error.code === 'ENOENT') {
            console.log('🤖 Robô: "O arquivo arquivo-criado.txt não existe!"');
            console.log('💡 Dica: Execute o script de escrever primeiro.');
        }
    }
}

// 🚀 PASSO 4: Manda o robô trabalhar!
lerMeuArquivo();
🚀 Passo 3: Execute o código

Agora vamos fazer o robô trabalhar!

💻 Como executar (passo a passo):

  1. 1. Abra o terminal (prompt de comando)
  2. 2. Navegue até a pasta do seu projeto
  3. 3. Digite o comando abaixo e pressione Enter:
node ler-arquivo.js

✅ Resultado esperado:

🤖 Robô: "Vou tentar ler o arquivo dados.txt..."
✅ Robô: "Consegui ler! Aqui está:"
📄 Conteúdo que o robô encontrou:
──────────────────────────────
Olá! Este é um arquivo de teste.
Esta é a segunda linha.
E esta é a terceira linha!
──────────────────────────────

❌ Se der erro:

  • • Verifique se o arquivo dados.txt existe
  • • Verifique se está na pasta correta
  • • Verifique se o nome do arquivo está correto

✍️ 2. Escrevendo um Arquivo

Como fazer o Node.js "criar" ou "modificar" um arquivo

Código para escrever arquivo
// escrever-arquivo.js
const fs = require('fs').promises;

// Função para escrever arquivo
async function escreverMeuArquivo() {
    try {
        console.log('✍️ Criando um novo arquivo...');
        
        // Conteúdo que queremos escrever
        const meuTexto = `Arquivo criado pelo Node.js!
Data: ${new Date().toLocaleString()}
Este arquivo foi gerado automaticamente.`;
        
        // Escrever o arquivo (se não existir, cria; se existir, substitui)
        await fs.writeFile('arquivo-criado.txt', meuTexto, 'utf8');
        
        console.log('✅ Arquivo "arquivo-criado.txt" criado com sucesso!');
        console.log('📄 Conteúdo escrito:');
        console.log('─'.repeat(40));
        console.log(meuTexto);
        console.log('─'.repeat(40));
        
    } catch (error) {
        console.error('❌ Erro ao escrever arquivo:', error.message);
    }
}

// Executar a função
escreverMeuArquivo();
💡 Dicas importantes:
  • writeFile sempre substitui o arquivo inteiro
  • Se o arquivo não existir, ele será criado automaticamente
  • Se o arquivo existir, o conteúdo antigo será perdido
  • Para adicionar ao final, use appendFile em vez de writeFile

🔍 3. Verificando se um Arquivo Existe

Como "perguntar" ao sistema se um arquivo está lá

Código para verificar arquivos
// verificar-arquivo.js
const fs = require('fs').promises;

// Função para verificar se arquivo existe
async function verificarArquivo(nomeArquivo) {
    try {
        console.log(`🔍 Verificando se "${nomeArquivo}" existe...`);
        
        // Tenta "acessar" o arquivo
        await fs.access(nomeArquivo);
        
        console.log(`✅ O arquivo "${nomeArquivo}" existe!`);
        return true;
        
    } catch (error) {
        console.log(`❌ O arquivo "${nomeArquivo}" NÃO existe.`);
        return false;
    }
}

// Função principal para testar vários arquivos
async function testarArquivos() {
    console.log('=== VERIFICANDO ARQUIVOS ===\n');
    
    // Lista de arquivos para verificar
    const arquivos = [
        'dados.txt',
        'arquivo-criado.txt',
        'arquivo-inexistente.txt',
        'package.json'
    ];
    
    // Verificar cada arquivo
    for (const arquivo of arquivos) {
        await verificarArquivo(arquivo);
        console.log(''); // Linha em branco
    }
    
    console.log('=== VERIFICAÇÃO CONCLUÍDA ===');
}

// Executar os testes
testarArquivos();

// Exemplo mais avançado: verificar e criar se não existir
async function garantirArquivo(nomeArquivo, conteudoPadrao) {
    const existe = await verificarArquivo(nomeArquivo);
    
    if (!existe) {
        console.log(`📝 Criando arquivo "${nomeArquivo}" com conteúdo padrão...`);
        await fs.writeFile(nomeArquivo, conteudoPadrao, 'utf8');
        console.log(`✅ Arquivo "${nomeArquivo}" criado!`);
    }
}

// Teste da função avançada
async function exemploAvancado() {
    await garantirArquivo('config.txt', 'configuracao=padrao\nversao=1.0');
}

📁 4. Trabalhando com Pastas (Diretórios)

Como criar e listar pastas

Criando uma pasta
// trabalhar-pastas.js
const fs = require('fs').promises;

// Função para criar uma pasta
async function criarPasta(nomePasta) {
    try {
        console.log(`📁 Criando pasta "${nomePasta}"...`);
        
        // Criar a pasta
        await fs.mkdir(nomePasta);
        
        console.log(`✅ Pasta "${nomePasta}" criada com sucesso!`);
        
    } catch (error) {
        if (error.code === 'EEXIST') {
            console.log(`⚠️ A pasta "${nomePasta}" já existe.`);
        } else {
            console.error('❌ Erro ao criar pasta:', error.message);
        }
    }
}

// Função para listar arquivos de uma pasta
async function listarArquivos(nomePasta) {
    try {
        console.log(`📋 Listando arquivos da pasta "${nomePasta}":`);
        
        // Ler conteúdo da pasta
        const arquivos = await fs.readdir(nomePasta);
        
        if (arquivos.length === 0) {
            console.log('   (pasta vazia)');
        } else {
            arquivos.forEach((arquivo, index) => {
                console.log(`   ${index + 1}. ${arquivo}`);
            });
        
        // Código continua normalmente aqui
        }
        
    } catch (error) {
        console.error(`❌ Erro ao listar pasta "${nomePasta}":`, error.message);
    }
}

// Função principal
async function exemploComPastas() {
    console.log('=== TRABALHANDO COM PASTAS ===\n');
    
    // Criar uma pasta de teste
    await criarPasta('minha-pasta-teste');
    console.log('');
    
    // Listar arquivos da pasta atual
    await listarArquivos('.');
    console.log('');
    
    // Listar arquivos da pasta que criamos
    await listarArquivos('minha-pasta-teste');
    
    console.log('\n=== EXEMPLO CONCLUÍDO ===');
}

// Executar o exemplo
exemploComPastas();

🚨 Problemas Comuns e Soluções

Erro: "ENOENT: no such file or directory"

Problema: O arquivo ou pasta não existe

Soluções:

  • • Verifique se o nome do arquivo está correto
  • • Certifique-se de que o arquivo está na mesma pasta do seu script
  • • Use caminhos absolutos se necessário: C:\\Users\\SeuNome\\arquivo.txt

Erro: "EACCES: permission denied"

Problema: Sem permissão para acessar o arquivo

Soluções:

  • • Execute o terminal como administrador
  • • Verifique se o arquivo não está sendo usado por outro programa
  • • Mude as permissões do arquivo

Erro: "EEXIST: file already exists"

Problema: Tentando criar algo que já existe

Soluções:

  • • Use fs.access() para verificar antes de criar
  • • Use { recursive: true } para pastas
  • • Delete o arquivo/pasta existente primeiro

5. Manipulação de Caminhos (path) - Navegando pelo Sistema

🗺️ Analogia: Caminhos como Endereços

Imagine que os arquivos no computador são como casas em uma cidade:

  • Caminho absoluto: Como um endereço completo: "Rua das Flores, 123, Bairro Centro, São Paulo, SP"
  • Caminho relativo: Como uma direção: "duas casas à direita da minha"
  • Nome do arquivo: Como o nome da pessoa que mora na casa
  • Extensão: Como o tipo da casa (apartamento, casa, sobrado)

🤔 O que é esse tal de "path"?

Imagina que você é um carteiro 📮 e precisa entregar cartas em casas diferentes. O módulo path é como seu "manual do carteiro" que te ensina:

  • 🏠 Como escrever endereços direito - "Rua das Flores, 123"
  • 🗺️ Como encontrar o endereço completo - "São Paulo, SP, Brasil"
  • ✂️ Como separar as partes - Rua, número, cidade
  • 🌍 Como funcionar em qualquer país - Brasil, EUA, Japão
  • 🔍 Como descobrir informações - "Essa casa é um apartamento?"

💡 Em outras palavras: O path te ajuda a trabalhar com "endereços de arquivos" no computador de forma inteligente!

🌍 Por que cada computador "fala" diferente?

Imagina que você está mandando uma carta 📬 Cada país tem um jeito diferente de escrever endereços:

🪟 Computadores Windows (como o Brasil)

Escrevem endereços assim:

C:\\Usuarios\\João\\Documentos\\arquivo.txt

• Usa \\ (barra "para trás")

• Tem "letras de gaveta" (C:, D:, E:)

🐧 Computadores Linux/Mac (como os EUA)

Escrevem endereços assim:

/home/joao/documentos/arquivo.txt

• Usa / (barra "normal")

• Sempre começa com /

🎯 É aqui que o path salva o dia! Ele é como um "tradutor automático" que escreve o endereço no jeito certo para cada computador! 🤖

🛠️ Principais Métodos do Path

🧩 1. path.join() - "Colando" pedaços de endereço

É como montar um quebra-cabeça de endereço! 🧩 Você tem os pedaços e o path.join() cola tudo certinho.

🎯 Vamos ver na prática!
// 🧩 Montando endereços como quebra-cabeça
const path = require('path');

console.log('🏠 === MONTANDO ENDEREÇOS ===\n');

// 1️⃣ Juntando pedaços simples (como montar: "pasta1 + pasta2 + arquivo")
const endereco1 = path.join('pasta1', 'pasta2', 'arquivo.txt');
console.log('📁 Endereço 1:', endereco1);
// 🪟 No Windows fica: pasta1\\pasta2\\arquivo.txt
// 🐧 No Linux fica: pasta1/pasta2/arquivo.txt

// 2️⃣ Começando da pasta onde estou agora (o "." significa "aqui")
const endereco2 = path.join('.', 'documentos', 'relatorio.pdf');
console.log('📄 Endereço 2:', endereco2);
// Resultado: "aqui/documentos/relatorio.pdf"

// 3️⃣ Subindo uma pasta (o ".." significa "pasta de cima")
const endereco3 = path.join('..', 'backup', 'dados.json');
console.log('💾 Endereço 3:', endereco3);
// Resultado: "pasta-de-cima/backup/dados.json"

// 4️⃣ Endereço bem grande (como montar um endereço completo)
const endereco4 = path.join('usuarios', 'joao', 'projetos', 'meu-app', 'index.js');
console.log('🚀 Endereço 4:', endereco4);
// O path.join() monta tudo certinho automaticamente!
🤔 Por que não posso só "colar" com +?

❌ Jeito errado (quebra!):

'pasta1' + '/' + 'arquivo.txt'

☝️ Isso quebra no Windows porque ele usa \\ em vez de /

✅ Jeito certo (sempre funciona!):

path.join('pasta1', 'arquivo.txt')

☝️ O path.join() é inteligente e escolhe a barra certa!

🗺️ 2. path.resolve() - "Onde fica isso mesmo?"

É como pedir o endereço completo! 📮 Você fala "casa do João" e ele te dá "Rua das Flores, 123, São Paulo, SP, Brasil"

Exemplo prático
// caminho-absoluto.js
const path = require('path');

console.log('=== CAMINHOS ABSOLUTOS ===\n');

// Descobrir onde estamos agora
console.log('📂 Pasta atual:', process.cwd());
console.log('');

// Resolver caminho relativo para absoluto
const absoluto1 = path.resolve('documentos', 'arquivo.txt');
console.log('📄 Arquivo 1 (absoluto):', absoluto1);
// Resultado: /caminho/completo/para/sua/pasta/atual/documentos/arquivo.txt

// Resolver múltiplos caminhos
const absoluto2 = path.resolve('..', 'backup', 'dados.json');
console.log('📄 Arquivo 2 (absoluto):', absoluto2);
// Resultado: /caminho/completo/para/pasta/pai/backup/dados.json

// Se já for absoluto, retorna como está
const absoluto3 = path.resolve('/home/usuario/arquivo.txt');
console.log('📄 Arquivo 3 (já absoluto):', absoluto3);
// Resultado: /home/usuario/arquivo.txt

// Exemplo prático: arquivo de configuração
const configPath = path.resolve('config', 'database.json');
console.log('⚙️ Configuração:', configPath);

console.log('\n=== DIFERENÇA ENTRE JOIN E RESOLVE ===');
console.log('join("docs", "file.txt")   :', path.join('docs', 'file.txt'));
console.log('resolve("docs", "file.txt"):', path.resolve('docs', 'file.txt'));
🤔 Diferença entre join() e resolve()
  • path.join(): Apenas "cola" os pedaços (pode ser relativo)
  • path.resolve(): Sempre retorna o caminho completo (absoluto)
  • Quando usar resolve(): Quando precisa do caminho completo
  • Quando usar join(): Quando quer manter relativo

🔍 3. Extraindo Informações do Caminho

Como "quebrar" um caminho em pedaços úteis

Métodos para extrair informações
// extrair-info.js
const path = require('path');

console.log('=== EXTRAINDO INFORMAÇÕES ===\n');

// Caminho de exemplo
const arquivoCompleto = '/home/usuario/projetos/meu-app/src/index.js';
console.log('📁 Caminho original:', arquivoCompleto);
console.log('');

// Extrair o nome do arquivo (com extensão)
const nomeArquivo = path.basename(arquivoCompleto);
console.log('📄 Nome do arquivo:', nomeArquivo);
// Resultado: index.js

// Extrair o nome sem extensão
const nomeSemExtensao = path.basename(arquivoCompleto, '.js');
console.log('📝 Nome sem extensão:', nomeSemExtensao);
// Resultado: index

// Extrair a extensão
const extensao = path.extname(arquivoCompleto);
console.log('🏷️ Extensão:', extensao);
// Resultado: .js

// Extrair a pasta pai (diretório)
const pastaPai = path.dirname(arquivoCompleto);
console.log('📂 Pasta pai:', pastaPai);
// Resultado: /home/usuario/projetos/meu-app/src

console.log('\n=== EXEMPLO PRÁTICO ===');

// Função para analisar qualquer arquivo
function analisarArquivo(caminhoArquivo) {
    console.log(`\n🔍 Analisando: ${caminhoArquivo}`);
    console.log('─'.repeat(50));
    console.log('📄 Nome completo  :', path.basename(caminhoArquivo));
    console.log('📝 Nome sem ext.  :', path.basename(caminhoArquivo, path.extname(caminhoArquivo)));
    console.log('🏷️ Extensão      :', path.extname(caminhoArquivo));
    console.log('📂 Pasta         :', path.dirname(caminhoArquivo));
    console.log('📍 Absoluto      :', path.resolve(caminhoArquivo));
}

// Testar com diferentes arquivos
analisarArquivo('documento.pdf');
analisarArquivo('fotos/ferias.jpg');
analisarArquivo('../backup/dados.json');
analisarArquivo('C:\\Users\\João\\Desktop\\apresentacao.pptx');

🚀 4. Exemplo Prático: Organizador de Arquivos

Um programa que organiza arquivos por tipo usando path

Organizador automático
// organizador-arquivos.js
const path = require('path');
const fs = require('fs').promises;

// Função para organizar arquivos por extensão
async function organizarArquivos() {
    try {
        console.log('📁 ORGANIZADOR DE ARQUIVOS\n');
        
        // Ler todos os arquivos da pasta atual
        const arquivos = await fs.readdir('.');
        
        // Filtrar apenas arquivos (não pastas)
        const apenasArquivos = [];
        for (const item of arquivos) {
            const stats = await fs.stat(item);
            if (stats.isFile()) {
                apenasArquivos.push(item);
            }
        }
        
        console.log(`📋 Encontrados ${apenasArquivos.length} arquivos:`);
        
        // Analisar cada arquivo
        for (const arquivo of apenasArquivos) {
            const extensao = path.extname(arquivo);
            const nome = path.basename(arquivo, extensao);
            const tamanho = (await fs.stat(arquivo)).size;
            
            console.log(`\n📄 ${arquivo}`);
            console.log(`   📝 Nome: ${nome}`);
            console.log(`   🏷️ Tipo: ${extensao || '(sem extensão)'}`);
            console.log(`   📏 Tamanho: ${tamanho} bytes`);
            
            // Sugerir pasta de destino baseada na extensão
            let pastaDestino;
            switch (extensao.toLowerCase()) {
                case '.jpg':
                case '.png':
                case '.gif':
                    pastaDestino = 'imagens';
                    break;
                case '.pdf':
                case '.doc':
                case '.docx':
                    pastaDestino = 'documentos';
                    break;
                case '.js':
                case '.html':
                case '.css':
                    pastaDestino = 'codigo';
                    break;
                default:
                    pastaDestino = 'outros';
            }
            
            console.log(`   📂 Sugestão: mover para pasta "${pastaDestino}"`);
            
            // Mostrar como seria o caminho final
            const caminhoFinal = path.join(pastaDestino, arquivo);
            console.log(`   📍 Caminho final: ${caminhoFinal}`);
        }
        
        console.log('\n✅ Análise concluída!');
        console.log('💡 Dica: Este é apenas um exemplo. Para mover os arquivos de verdade,');
        console.log('   você precisaria usar fs.rename() ou fs.copyFile().');
        
    } catch (error) {
        console.error('❌ Erro:', error.message);
    }
}

// Executar o organizador
organizarArquivos();
🎯 O que este exemplo ensina:
  • • Como usar path.extname() para identificar tipos de arquivo
  • • Como usar path.basename() para extrair nomes
  • • Como usar path.join() para criar novos caminhos
  • • Como combinar path com fs para trabalhar com arquivos reais

💡 Dicas e Melhores Práticas

✅ Faça sempre

  • • Use path.join() em vez de concatenar strings
  • • Use path.resolve() quando precisar de caminhos absolutos
  • • Use __dirname para referenciar a pasta do seu script
  • • Teste seu código em diferentes sistemas operacionais

❌ Evite fazer

  • • Nunca: 'pasta' + '/' + 'arquivo' (quebra no Windows)
  • • Nunca: 'C:\\pasta\\arquivo' (quebra no Linux/Mac)
  • • Nunca: assumir que todos usam o mesmo sistema que você
  • • Nunca: esquecer de tratar caminhos com espaços

🔧 Variáveis úteis

// Pasta onde está o seu script
console.log('Script está em:', __dirname);

// Arquivo atual (com nome)
console.log('Arquivo atual:', __filename);

// Pasta de trabalho atual
console.log('Pasta de trabalho:', process.cwd());

// Separador do sistema (/ ou \\)
console.log('Separador:', path.sep);

6. Exercícios Práticos

🎯 Objetivo dos Exercícios

Agora vamos colocar a mão na massa! Estes exercícios vão te ajudar a praticar tudo que aprendemos sobre módulos, arquivos e caminhos. Não se preocupe se parecer difícil no início - vamos explicar cada linha de código!

📋 Preparação Detalhada (Passo a Passo):

🎯 PASSO 1: Preparando o Ambiente
  1. Abra o VS Code: Clique no ícone do VS Code na sua área de trabalho ou menu iniciar
  2. Crie uma pasta nova:
    • Vá até sua área de trabalho (Desktop)
    • Clique com botão direito em um espaço vazio
    • Escolha "Nova pasta" ou "Criar pasta"
    • Digite o nome: exercicios-aula2
    • Pressione Enter
  3. Abra a pasta no VS Code:
    • No VS Code, clique em "Arquivo" (File) no menu superior
    • Clique em "Abrir Pasta" (Open Folder)
    • Navegue até sua área de trabalho
    • Selecione a pasta "exercicios-aula2"
    • Clique em "Selecionar Pasta"
  4. Abra o terminal:
    • No VS Code, clique em "Terminal" no menu superior
    • Clique em "Novo Terminal" (New Terminal)
    • Uma janela preta vai aparecer na parte de baixo
    • Você deve ver algo como: C:\Users\SeuNome\Desktop\exercicios-aula2>
✅ Como saber se deu certo?
  • No lado esquerdo do VS Code, você deve ver "EXERCICIOS-AULA2" como nome da pasta
  • O terminal deve mostrar o caminho da sua pasta
  • Quando você digitar dir (Windows) ou ls (Mac/Linux) no terminal, deve mostrar uma pasta vazia
🆘 Se algo der errado:
  • VS Code não abre: Verifique se está instalado. Se não, baixe em code.visualstudio.com
  • Não consegue criar pasta: Tente criar diretamente no Windows Explorer
  • Terminal não abre: Use Ctrl+Shift+` (acento grave) como atalho
  • Caminho errado no terminal: Use cd Desktop\exercicios-aula2 para navegar

📝 Exercício 1: Sistema de Logger

O que vamos fazer: Criar um sistema que salva mensagens em um arquivo de log. É como um "diário" do seu programa - tudo que acontece fica registrado!

🔧 Passo a Passo:

  1. Crie o arquivo: No VS Code, clique com botão direito na pasta → "Novo Arquivo" → digite "logger.js"
  2. Digite o código: Copie o código abaixo (vamos explicar cada parte depois)
  3. Salve o arquivo: Ctrl+S (Windows) ou Cmd+S (Mac)
// logger.js - Sistema de Logger para nossa aplicação

// 1. IMPORTAÇÕES - Trazendo as ferramentas que vamos usar
const fs = require('fs').promises;  // Sistema de arquivos (jeito moderno que não trava)
const path = require('path');        // Manipulação de caminhos

// 2. CLASSE LOGGER - Nossa "fábrica" de logs
class Logger {
    // CONSTRUTOR - Executa quando criamos um novo Logger
    constructor(logFile = 'app.log') {
        // __dirname = pasta atual do arquivo
        // path.join = junta caminhos de forma segura
        this.logFile = path.join(__dirname, logFile);
        console.log(`📝 Logger criado! Arquivo: ${this.logFile}`);
    }
    
    // MÉTODO PRINCIPAL - Escreve qualquer tipo de log
    async log(message, level = 'INFO') {
        // Cria um "carimbo de data e hora" (tipo: 2024-01-15 às 10:30:45)
        const timestamp = new Date().toISOString(); // Pega a data/hora atual e transforma em texto
        
        // Monta a linha do log: [DATA] NÍVEL: MENSAGEM
        const logEntry = `[${timestamp}] ${level}: ${message}\n`;
        
        try {
            // appendFile = "cola" no final do arquivo (como escrever no final de um caderno)
            await fs.appendFile(this.logFile, logEntry);
            console.log(`✅ Log salvo: ${level} - ${message}`);
        } catch (error) {
            console.error('❌ Erro ao escrever log:', error.message);
        }
    }
    
    // MÉTODO DE CONVENIÊNCIA - Para logs informativos
    async info(message) {
        await this.log(message, 'INFO');
    }
    
    // MÉTODO DE CONVENIÊNCIA - Para logs de erro
    async error(message) {
        await this.log(message, 'ERROR');
    }
    
    // MÉTODO EXTRA - Para logs de aviso
    async warn(message) {
        await this.log(message, 'WARN');
    }
}

// EXPORTA a classe para outros arquivos usarem
module.exports = Logger;

📝 Exercício 2: Explorador de Arquivos

Vamos criar um "explorador" que encontra todos os arquivos dentro de uma pasta e suas subpastas. É como um "buscar arquivos" do Windows, mas feito por nós!

🎯 O que este código faz:

  • Entra em uma pasta
  • Lista tudo que tem dentro
  • Se encontrar outra pasta, entra nela também (recursão)
  • Coleta todos os arquivos encontrados
  • Retorna uma lista completa

🔧 Passo a Passo:

  1. Crie o arquivo: fileExplorer.js
  2. Digite o código: Copie o código abaixo
  3. Entenda cada parte: Leia os comentários
// fileExplorer.js - Explorador de arquivos recursivo

// IMPORTAÇÕES - Ferramentas que vamos usar
const fs = require('fs').promises;  // Sistema de arquivos (versão Promise)
const path = require('path');        // Manipulação de caminhos

// FUNÇÃO PRINCIPAL - Lista todos os arquivos recursivamente
async function listarArquivos(diretorio) {
    console.log(`🔍 Explorando: ${diretorio}`);
    
    // Array para guardar todos os arquivos encontrados
    const arquivos = [];
    
    try {
        // Lê o conteúdo do diretório (lista tudo que tem dentro)
        const items = await fs.readdir(diretorio);
        console.log(`📂 Encontrados ${items.length} itens em: ${diretorio}`);
        
        // Para cada item encontrado...
        for (const item of items) {
            // Monta o caminho completo do item
            const fullPath = path.join(diretorio, item);
            
            // Pega informações sobre o item (é pasta ou arquivo?)
            const stats = await fs.stat(fullPath);
            
            // Se for uma pasta (diretório)...
            if (stats.isDirectory()) {
                console.log(`📁 Pasta encontrada: ${item}`);
                
                // RECURSÃO: a função chama ela mesma (como bonecas russas, uma dentro da outra)
                const subArquivos = await listarArquivos(fullPath);
                
                // Adiciona todos os arquivos da subpasta ao nosso array
                // O "..." espalha os elementos (como despejar uma caixa dentro de outra)
                arquivos.push(...subArquivos);
            } else {
                // Se for um arquivo, adiciona ao array
                console.log(`📄 Arquivo encontrado: ${item}`);
                arquivos.push(fullPath);
            }
        }
    } catch (error) {
        // Se der erro (pasta não existe, sem permissão, etc.)
        console.error(`❌ Erro ao explorar ${diretorio}:`, error.message);
    }
    
    return arquivos;
}

// FUNÇÃO AUXILIAR - Mostra os resultados de forma organizada
function mostrarResultados(arquivos) {
    console.log('\n📊 RELATÓRIO FINAL:');
    console.log(`Total de arquivos encontrados: ${arquivos.length}`);
    
    if (arquivos.length > 0) {
        console.log('\n📋 Lista de arquivos:');
        arquivos.forEach((arquivo, index) => {
            console.log(`${index + 1}. ${arquivo}`);
        });
    }
}

// EXPORTA as funções para outros arquivos usarem
module.exports = { 
    listarArquivos, 
    mostrarResultados 
};

🧪 Como Testar o Explorador:

1. Crie um arquivo de teste (test-explorer.js):

// test-explorer.js - Teste do explorador de arquivos

// Importa nossas funções
const { listarArquivos, mostrarResultados } = require('./fileExplorer');
const path = require('path');

// Função principal de teste
async function testarExplorador() {
    console.log('🚀 Iniciando teste do Explorador de Arquivos...');
    
    // Testa com a pasta atual (onde está o arquivo)
    const pastaAtual = __dirname;
    console.log(`📂 Pasta a ser explorada: ${pastaAtual}`);
    
    try {
        // Executa a exploração
        const arquivos = await listarArquivos(pastaAtual);
        
        // Mostra os resultados
        mostrarResultados(arquivos);
        
        console.log('\n✅ Teste concluído com sucesso!');
    } catch (error) {
        console.error('❌ Erro durante o teste:', error.message);
    }
}

// Executa o teste
testarExplorador();

2. Execute no terminal:

# Execute o teste

node test-explorer.js

3. Exemplo de resultado:

🚀 Iniciando teste do Explorador de Arquivos...

📂 Pasta a ser explorada: C:\sua\pasta

🔍 Explorando: C:\sua\pasta

📂 Encontrados 3 itens em: C:\sua\pasta

📄 Arquivo encontrado: logger.js

📄 Arquivo encontrado: fileExplorer.js

📄 Arquivo encontrado: test-explorer.js

📊 RELATÓRIO FINAL:

Total de arquivos encontrados: 3

✅ Teste concluído com sucesso!

🎯 Desafio Extra:

Tente modificar o código para:

  • Filtrar apenas arquivos .js
  • Mostrar o tamanho de cada arquivo
  • Contar quantas pastas foram exploradas
  • Salvar o resultado em um arquivo .txt

7. 🏗️ Projeto Aplicado Completo: Sistema da Padaria

🎯 Objetivo do Projeto

Vamos criar um sistema completo para a Padaria Doce Sabor usando TUDO que aprendemos nesta aula: módulos, arquivos, caminhos e organização de código. Este será nosso primeiro projeto "real"!

📋 O que o sistema vai fazer:

  • Gerenciar produtos da padaria (pães, bolos, doces)
  • Organizar por categorias
  • Salvar dados em arquivos JSON
  • Criar logs de todas as operações
  • Estrutura profissional de pastas

📁 Passo 1: Criando a Estrutura de Pastas

Primeiro, vamos criar uma estrutura organizada. É como organizar uma casa - cada coisa tem seu lugar!

🔧 Como criar (passo a passo):

  1. Abra o terminal na sua área de trabalho
  2. Digite: mkdir padaria-doce-sabor (cria a pasta principal)
  3. Entre na pasta: cd padaria-doce-sabor
  4. Crie as subpastas: Execute os comandos abaixo um por um

# Comandos para criar a estrutura completa

mkdir src

mkdir src\models

mkdir src\controllers

mkdir src\utils

mkdir src\config

mkdir data

mkdir logs

mkdir tests

🏗️ Estrutura Final:

padaria-doce-sabor/
├── 📁 src/                    ← Código principal
│   ├── 📁 models/             ← "Moldes" dos dados (Produto, Categoria)
│   │   ├── 📄 Product.js      ← Define como é um produto
│   │   └── 📄 Category.js     ← Define como é uma categoria
│   ├── 📁 controllers/        ← "Controladores" (lógica de negócio)
│   │   ├── 📄 productController.js  ← Gerencia produtos
│   │   └── 📄 categoryController.js ← Gerencia categorias
│   ├── 📁 utils/              ← Ferramentas auxiliares
│   │   ├── 📄 logger.js       ← Sistema de logs
│   │   └── 📄 fileHelper.js   ← Ajuda com arquivos
│   └── 📁 config/             ← Configurações
│       └── 📄 database.js     ← Config do "banco de dados"
├── 📁 data/                   ← Dados salvos (JSON)
│   ├── 📄 products.json      ← Lista de produtos
│   └── 📄 categories.json    ← Lista de categorias
├── 📁 logs/                   ← Arquivos de log
├── 📁 tests/                  ← Testes do sistema
├── 📄 package.json           ← Informações do projeto
└── 📄 app.js                  ← Arquivo principal
💡 Por que organizar assim?
  • src/: Todo código fica separado dos dados
  • models/: Define a "forma" dos nossos dados
  • controllers/: Contém a lógica (o "cérebro")
  • utils/: Ferramentas que usamos em vários lugares
  • data/: Arquivos JSON com os dados reais
  • logs/: Histórico do que aconteceu no sistema

🚀 Passo 1.5: Inicializando o Projeto Node.js

Antes de criar os arquivos de código, precisamos "avisar" ao Node.js que este é um projeto oficial!

⚠️ IMPORTANTE: Faça isso ANTES de criar os arquivos .js!

O package.json é como o "documento de identidade" do nosso projeto. Sem ele, o Node.js não consegue entender direito nosso sistema!

🔧 Comandos para executar:

# Certifique-se de estar na pasta do projeto

cd padaria-doce-sabor

# Inicializar o projeto Node.js

npm init -y

O comando npm init -y criará automaticamente o arquivo package.json com configurações padrão. O -y significa "sim para tudo"!

✅ O que aconteceu?

Foi criado o arquivo package.json na raiz do projeto com informações como:

  • • Nome do projeto
  • • Versão atual
  • • Arquivo principal (main)
  • • Scripts para executar o projeto

Agora sim podemos criar nossos arquivos .js!

🏷️ Passo 2: Criando os "Moldes" dos Nossos Dados

Vamos criar "moldes" para organizar nossos dados! É como ter uma ficha padrão para cada produto da padaria. 📋

🤔 O que é um "Molde" (Modelo)?

🍞 Exemplo simples: Quando você vai comprar pão na padaria, o vendedor sempre pergunta as mesmas coisas:

  • • "Qual pão você quer?" (nome)
  • • "Quanto custa?" (preço)
  • • "É doce ou salgado?" (categoria)

💡 O molde é isso: uma "fichinha" que sempre tem os mesmos campos para preencher!

📄 Primeiro arquivo: src/models/Product.js

🍞 Vamos criar nossa "fichinha" de produto! Cada produto da padaria vai ter as mesmas informações.

🎯 Passo 1: Entendendo o que vamos fazer

Imagine que você tem uma fichinha para cada produto da padaria:

  • 📝 Nome: "Pão Francês"
  • 💰 Preço: R$ 0,50
  • 📖 Descrição: "Pão fresquinho"
  • 📂 Tipo: "Pães"
🎯 Passo 2: Criando o código (bem simples!)

Vamos criar linha por linha, explicando cada pedacinho:

// src/models/Product.js
// 📝 Este arquivo é nossa "fichinha" de produto

// 🏗️ PASSO 1: Criamos a "classe" (o molde)
class Product {
    // 🎯 PASSO 2: O "constructor" é como preencher a fichinha
    // Quando alguém criar um produto, vai dar essas informações:
    constructor(id, name, description, price, categoryId, imageUrl) {
        
        // 📋 PASSO 3: Guardamos as informações que a pessoa deu
        this.id = id;                    // 🔢 Número do produto (1, 2, 3...)
        this.name = name;                // 📝 Nome ("Pão Francês")
        this.description = description;   // 📖 Descrição ("Pão fresquinho")
        this.price = price;              // 💰 Preço (0.50)
        this.categoryId = categoryId;    // 📂 Tipo (1 = Pães)
        this.imageUrl = imageUrl;        // 📷 Foto ("pao.jpg")
        
        // 🤖 PASSO 4: O computador preenche algumas coisas sozinho
        this.available = true;           // ✅ Está disponível? (sempre sim no início)
        this.createdAt = new Date();     // 📅 Quando foi criado (agora)
        this.updatedAt = new Date();     // 📅 Última vez que mudou (agora)
    }
    
    // 🎯 PASSO 5: Funções úteis para trabalhar com o produto
    
    // 💾 Função para salvar no arquivo (transforma em JSON)
    toJSON() {
        // JSON é como uma "lista organizada" que o computador entende
        return {
            id: this.id,
            name: this.name,
            description: this.description,
            price: this.price,
            categoryId: this.categoryId,
            imageUrl: this.imageUrl,
            available: this.available,
            createdAt: this.createdAt,
            updatedAt: this.updatedAt
        };
    }
    
    // ✏️ Função para mudar informações do produto
    update(newData) {
        // Só muda o que a pessoa mandou mudar
        if (newData.name) this.name = newData.name;           // Novo nome?
        if (newData.description) this.description = newData.description; // Nova descrição?
        if (newData.price) this.price = newData.price;        // Novo preço?
        if (newData.categoryId) this.categoryId = newData.categoryId; // Nova categoria?
        if (newData.imageUrl) this.imageUrl = newData.imageUrl; // Nova foto?
        if (newData.available !== undefined) this.available = newData.available; // Disponível?
        
        // 📅 Sempre marca quando foi a última mudança
        this.updatedAt = new Date();
    }
    
    // 💰 Função para mostrar o preço bonitinho (R$ 1,50)
    getFormattedPrice() {
        // Transforma 1.5 em "R$ 1,50"
        return `R$ ${this.price.toFixed(2).replace('.', ',')}`;
    }
    
    // ✅ Função para ver se o produto está disponível
    isAvailable() {
        return this.available === true;
    }
}

// 📤 PASSO 6: Deixa outros arquivos usarem esta "fichinha"
// É como emprestar o molde para outros arquivos
module.exports = Product;
🧪 Vamos testar nossa "fichinha"!

Agora vamos criar um pão de verdade usando nosso molde:

// 🥖 PASSO 1: Pegar nosso molde de produto
const Product = require('./models/Product');

// 🥖 PASSO 2: Criar um pão francês usando o molde
const paoFrances = new Product(
    1,                           // Número da fichinha
    'Pão Francês',              // Nome do pão
    'Pão fresquinho do dia',    // O que tem de especial
    0.50,                       // Quanto custa (50 centavos)
    1,                          // Que tipo é (1 = Pães)
    'pao-frances.jpg'           // Foto do pão
);

// 🎯 PASSO 3: Vamos ver como ficou!
console.log('Preço bonitinho:', paoFrances.getFormattedPrice()); // "R$ 0,50"
console.log('Está disponível?', paoFrances.isAvailable());       // true

// 🎉 Pronto! Nossa fichinha de pão está funcionando!

💡 O que aconteceu aqui?

Criamos uma "fichinha" de pão francês com todas as informações importantes. É como preencher uma etiqueta de produto na padaria!

📂 Arquivo: src/models/Category.js

🏷️ O que é uma Categoria?

É como as "seções" da padaria: Pães, Bolos, Doces, etc. Cada seção agrupa produtos parecidos!

🎯 PASSO 1: Criando o molde da "seção"

Vamos fazer uma fichinha para cada seção da padaria (Pães, Bolos, etc.)

// 📂 PASSO 1: Criando o molde de uma "seção" da padaria
class Category {
    // 🏗️ PASSO 2: Função que roda quando criamos uma nova seção
    constructor(id, name, description, icon) {
        // 📝 Informações que a pessoa precisa dar:
        this.id = id;                    // Número da seção (1, 2, 3...)
        this.name = name;                // Nome da seção ("Pães", "Bolos"...)
        this.description = description;   // O que tem nesta seção
        this.icon = icon;                // Emoji da seção (🍞, 🎂...)
        
        // 🤖 Informações que o computador preenche sozinho:
        this.active = true;              // Seção está funcionando?
        this.createdAt = new Date();     // Quando foi criada
        this.productCount = 0;           // Quantos produtos tem aqui
    }
    
    // 🎯 PASSO 3: Funções úteis para trabalhar com a seção
    
    // 💾 Função para salvar no arquivo (transforma em JSON)
    toJSON() {
        // JSON é como uma "lista organizada" que o computador entende
        return {
            id: this.id,
            name: this.name,
            description: this.description,
            icon: this.icon,
            active: this.active,
            createdAt: this.createdAt,
            productCount: this.productCount
        };
    }
    
    // ✏️ Função para mudar informações da seção
    update(newData) {
        // Só muda o que a pessoa mandou mudar
        if (newData.name) this.name = newData.name;           // Novo nome?
        if (newData.description) this.description = newData.description; // Nova descrição?
        if (newData.icon) this.icon = newData.icon;           // Novo emoji?
        if (newData.active !== undefined) this.active = newData.active; // Ativar/desativar?
    }
    
    // ➕ Função para quando colocamos um produto na seção
    addProduct() {
        this.productCount++; // Conta +1 produto
    }
    
    // ➖ Função para quando tiramos um produto da seção
    removeProduct() {
        if (this.productCount > 0) {
            this.productCount--; // Conta -1 produto (se tiver algum)
        }
    }
}

// 📤 PASSO 4: Deixa outros arquivos usarem esta "fichinha de seção"
// module.exports = como colocar nossa "fichinha" numa "caixinha" para outros usarem
module.exports = Category;
🧪 Vamos testar nossa "seção"!

Agora vamos criar a seção de pães da nossa padaria:

// 🍞 PASSO 1: Pegar nosso molde de seção
const Category = require('./models/Category');

// 🍞 PASSO 2: Criar a seção de pães
const secaoPaes = new Category(
    1,                                    // Número da seção
    'Pães',                              // Nome da seção
    'Pães frescos e quentinhos',         // O que tem de especial
    '🍞'                                 // Emoji da seção
);

// 🎯 PASSO 3: Vamos colocar um produto na seção!
secaoPaes.addProduct(); // Colocamos 1 pão
console.log('Quantos produtos temos?', secaoPaes.productCount); // 1

// 🎉 Pronto! Nossa seção de pães está funcionando!

💡 O que aconteceu aqui?

Criamos uma "seção" da padaria e colocamos um produto nela. É como organizar os produtos em prateleiras!

🛠️ Arquivo: utils/fileHelper.js

🔧 O que é um FileHelper?

É como um "assistente" que nos ajuda a trabalhar com arquivos. Ele sabe ler, escrever e organizar arquivos!

// 🔧 Pegamos as ferramentas que vamos usar
const fs = require('fs').promises;  // Para mexer com arquivos
const path = require('path');        // Para trabalhar com endereços

// 🛠️ Nosso assistente para arquivos
// static = funções que funcionam sem precisar criar um objeto primeiro
class FileHelper {
    // 📖 PASSO 1: Função para LER um arquivo JSON (como ler uma receita)
    static async readJSON(filePath) {
        try {
            // 📄 Lê o arquivo como se fosse um texto normal
            const data = await fs.readFile(filePath, 'utf8');
            // 🔄 JSON.parse = "tradutor" que transforma texto em informações que o computador entende
            // É como pegar uma receita escrita à mão e digitar no computador!
            return JSON.parse(data);
        } catch (error) {
            console.error('❌ Robô: "Ops! Não consegui ler este arquivo:", error);
            return null; // Retorna "nada" se deu erro
        }
    }
    
    // ✏️ PASSO 2: Função para ESCREVER um arquivo JSON (como escrever uma receita)
    static async writeJSON(filePath, data) {
        try {
            // 🔄 JSON.stringify = "tradutor" que transforma informações do computador em texto
            // É como pegar uma lista no computador e imprimir numa folha de papel!
            const jsonData = JSON.stringify(data, null, 2);
            // 💾 Salva o texto no arquivo (como guardar a receita numa gaveta)
            await fs.writeFile(filePath, jsonData, 'utf8');
            return true; // Deu certo!
        } catch (error) {
            console.error('❌ Robô: "Ops! Não consegui salvar este arquivo:", error);
            return false; // Deu erro!
        }
    }
    
    // 📁 Função para CRIAR uma pasta (se não existir)
    static async ensureDirectory(dirPath) {
        try {
            // Cria a pasta (e todas as pastas "de dentro" se precisar)
            // recursive = "vai criando pastas uma dentro da outra se precisar"
            await fs.mkdir(dirPath, { recursive: true });
            return true; // Deu certo!
        } catch (error) {
            console.error('❌ Ops! Não consegui criar a pasta:', error);
            return false; // Deu erro!
        }
    }
}

// 📤 PASSO 4: Deixa outros arquivos usarem nosso "assistente de arquivos"
// module.exports = como colocar o assistente numa "caixinha" para outros usarem
module.exports = FileHelper;

💡 Para que serve isso?

Este assistente nos ajuda a salvar e carregar as informações da padaria (produtos, categorias) em arquivos no computador!

🔄 O que é JSON? É como uma "linguagem universal" que o computador entende. Como se fosse um "dicionário" que traduz nossas listas para o computador!

📝 Passo 3: Controllers (Controladores)

Agora vamos criar os controladores que irão gerenciar as operações dos produtos e categorias:

📁 controllers/productController.js

const Product = require('../models/Product');
const FileHelper = require('../utils/FileHelper');
const path = require('path');

class ProductController {
    constructor() {
        this.dataPath = path.join(__dirname, '..', 'data', 'products.json');
        this.fileHelper = new FileHelper();
    }

    // Criar um novo produto
    async createProduct(productData) {
        try {
            // Carregar produtos existentes
            const products = await this.getAllProducts();
            
            // Criar novo produto
            const newProduct = new Product(
                productData.name,
                productData.price,
                productData.category,
                productData.description
            );
            
            // Adicionar à lista
            products.push(newProduct);
            
            // Salvar no arquivo
            await this.fileHelper.writeJSON(this.dataPath, products);
            
            console.log(`✅ Produto "${newProduct.name}" criado com sucesso!`);
            return newProduct;
        } catch (error) {
            console.error('❌ Erro ao criar produto:', error.message);
            throw error;
        }
    }

    // Listar todos os produtos
    async getAllProducts() {
        try {
            const products = await this.fileHelper.readJSON(this.dataPath);
            return products || [];
        } catch (error) {
            console.log('📁 Arquivo de produtos não encontrado, criando novo...');
            return [];
        }
    }

    // Buscar produto por ID
    async getProductById(id) {
        try {
            const products = await this.getAllProducts();
            const product = products.find(p => p.id === id);
            
            if (!product) {
                throw new Error(`Produto com ID ${id} não encontrado`);
            }
            
            return product;
        } catch (error) {
            console.error('❌ Erro ao buscar produto:', error.message);
            throw error;
        }
    }

    // Atualizar produto
    async updateProduct(id, updateData) {
        try {
            const products = await this.getAllProducts();
            const productIndex = products.findIndex(p => p.id === id);
            
            if (productIndex === -1) {
                throw new Error(`Produto com ID ${id} não encontrado`);
            }
            
            // Atualizar dados
            products[productIndex] = { ...products[productIndex], ...updateData };
            
            // Salvar no arquivo
            await this.fileHelper.writeJSON(this.dataPath, products);
            
            console.log(`✅ Produto "${products[productIndex].name}" atualizado!`);
            return products[productIndex];
        } catch (error) {
            console.error('❌ Erro ao atualizar produto:', error.message);
            throw error;
        }
    }

    // Deletar produto
    async deleteProduct(id) {
        try {
            const products = await this.getAllProducts();
            const productIndex = products.findIndex(p => p.id === id);
            
            if (productIndex === -1) {
                throw new Error(`Produto com ID ${id} não encontrado`);
            }
            
            const deletedProduct = products.splice(productIndex, 1)[0];
            
            // Salvar no arquivo
            await this.fileHelper.writeJSON(this.dataPath, products);
            
            console.log(`🗑️ Produto "${deletedProduct.name}" deletado!`);
            return deletedProduct;
        } catch (error) {
            console.error('❌ Erro ao deletar produto:', error.message);
            throw error;
        }
    }

    // Buscar produtos por categoria
    async getProductsByCategory(categoryName) {
        try {
            const products = await this.getAllProducts();
            return products.filter(p => p.category.toLowerCase() === categoryName.toLowerCase());
        } catch (error) {
            console.error('❌ Erro ao buscar produtos por categoria:', error.message);
            throw error;
        }
    }
}

module.exports = ProductController;

📁 controllers/categoryController.js

const Category = require('../models/Category');
const FileHelper = require('../utils/FileHelper');
const path = require('path');

class CategoryController {
    constructor() {
        this.dataPath = path.join(__dirname, '..', 'data', 'categories.json');
        this.fileHelper = new FileHelper();
    }

    // Criar nova categoria
    async createCategory(categoryData) {
        try {
            const categories = await this.getAllCategories();
            
            // Verificar se categoria já existe
            const existingCategory = categories.find(c => 
                c.name.toLowerCase() === categoryData.name.toLowerCase()
            );
            
            if (existingCategory) {
                throw new Error(`Categoria "${categoryData.name}" já existe!`);
            }
            
            const newCategory = new Category(
                categoryData.name,
                categoryData.description
            );
            
            categories.push(newCategory);
            await this.fileHelper.writeJSON(this.dataPath, categories);
            
            console.log(`✅ Categoria "${newCategory.name}" criada com sucesso!`);
            return newCategory;
        } catch (error) {
            console.error('❌ Erro ao criar categoria:', error.message);
            throw error;
        }
    }

    // Listar todas as categorias
    async getAllCategories() {
        try {
            const categories = await this.fileHelper.readJSON(this.dataPath);
            return categories || [];
        } catch (error) {
            console.log('📁 Arquivo de categorias não encontrado, criando novo...');
            return [];
        }
    }

    // Buscar categoria por ID
    async getCategoryById(id) {
        try {
            const categories = await this.getAllCategories();
            const category = categories.find(c => c.id === id);
            
            if (!category) {
                throw new Error(`Categoria com ID ${id} não encontrada`);
            }
            
            return category;
        } catch (error) {
            console.error('❌ Erro ao buscar categoria:', error.message);
            throw error;
        }
    }

    // Deletar categoria
    async deleteCategory(id) {
        try {
            const categories = await this.getAllCategories();
            const categoryIndex = categories.findIndex(c => c.id === id);
            
            if (categoryIndex === -1) {
                throw new Error(`Categoria com ID ${id} não encontrada`);
            }
            
            const deletedCategory = categories.splice(categoryIndex, 1)[0];
            await this.fileHelper.writeJSON(this.dataPath, categories);
            
            console.log(`🗑️ Categoria "${deletedCategory.name}" deletada!`);
            return deletedCategory;
        } catch (error) {
            console.error('❌ Erro ao deletar categoria:', error.message);
            throw error;
        }
    }
}

module.exports = CategoryController;

📝 Passo 4: Sistema de Logs

Vamos criar um sistema simples para registrar as operações do sistema:

📁 utils/logger.js

const fs = require('fs').promises;
const path = require('path');

class Logger {
    constructor() {
        this.logPath = path.join(__dirname, '..', 'logs', 'system.log');
        this.ensureLogDirectory();
    }

    // Garantir que o diretório de logs existe
    async ensureLogDirectory() {
        try {
            const logDir = path.dirname(this.logPath);
            await fs.mkdir(logDir, { recursive: true });
        } catch (error) {
            console.error('Erro ao criar diretório de logs:', error.message);
        }
    }

    // Registrar log
    async log(level, message, data = null) {
        try {
            const timestamp = new Date().toISOString();
            const logEntry = {
                timestamp,
                level: level.toUpperCase(),
                message,
                data
            };
            
            const logLine = JSON.stringify(logEntry) + '\n';
            await fs.appendFile(this.logPath, logLine);
            
            // Também exibir no console
            const emoji = this.getEmojiForLevel(level);
            console.log(`${emoji} [${timestamp}] ${level.toUpperCase()}: ${message}`);
            
        } catch (error) {
            console.error('Erro ao escrever log:', error.message);
        }
    }

    // Obter emoji para o nível do log
    getEmojiForLevel(level) {
        const emojis = {
            info: 'ℹ️',
            success: '✅',
            warning: '⚠️',
            error: '❌',
            debug: '🐛'
        };
        return emojis[level.toLowerCase()] || '📝';
    }

    // Métodos de conveniência
    async info(message, data = null) {
        await this.log('info', message, data);
    }

    async success(message, data = null) {
        await this.log('success', message, data);
    }

    async warning(message, data = null) {
        await this.log('warning', message, data);
    }

    async error(message, data = null) {
        await this.log('error', message, data);
    }

    async debug(message, data = null) {
        await this.log('debug', message, data);
    }

    // Ler logs
    async readLogs(lines = 50) {
        try {
            const content = await fs.readFile(this.logPath, 'utf8');
            const logLines = content.trim().split('\n');
            return logLines.slice(-lines).map(line => {
                try {
                    return JSON.parse(line);
                } catch {
                    return { message: line };
                }
            });
        } catch (error) {
            console.log('📁 Arquivo de log não encontrado');
            return [];
        }
    }
}

module.exports = Logger;

📝 Passo 5: Arquivo Principal (app.js)

Agora vamos criar o arquivo principal que irá demonstrar todo o sistema funcionando:

📁 app.js

const ProductController = require('./controllers/productController');
const CategoryController = require('./controllers/categoryController');
const Logger = require('./utils/logger');

class PadariaSystem {
    constructor() {
        this.productController = new ProductController();
        this.categoryController = new CategoryController();
        this.logger = new Logger();
    }

    // Inicializar sistema
    async init() {
        try {
            console.log('🍞 ===== SISTEMA DA PADARIA =====');
            console.log('🚀 Inicializando sistema...');
            
            await this.logger.info('Sistema da Padaria iniciado');
            
            // Criar categorias padrão
            await this.createDefaultCategories();
            
            // Criar produtos de exemplo
            await this.createSampleProducts();
            
            // Demonstrar funcionalidades
            await this.demonstrateFeatures();
            
            console.log('\n✅ Sistema inicializado com sucesso!');
            
        } catch (error) {
            await this.logger.error('Erro ao inicializar sistema', { error: error.message });
            console.error('❌ Erro ao inicializar:', error.message);
        }
    }

    // Criar categorias padrão
    async createDefaultCategories() {
        console.log('\n📂 Criando categorias padrão...');
        
        const defaultCategories = [
            { name: 'Pães', description: 'Pães frescos e artesanais' },
            { name: 'Doces', description: 'Doces e sobremesas deliciosas' },
            { name: 'Salgados', description: 'Salgados assados e fritos' },
            { name: 'Bebidas', description: 'Bebidas quentes e frias' }
        ];

        for (const categoryData of defaultCategories) {
            try {
                await this.categoryController.createCategory(categoryData);
                await this.logger.success(`Categoria criada: ${categoryData.name}`);
            } catch (error) {
                if (error.message.includes('já existe')) {
                    console.log(`⚠️ Categoria "${categoryData.name}" já existe`);
                } else {
                    await this.logger.error(`Erro ao criar categoria ${categoryData.name}`, { error: error.message });
                }
            }
        }
    }

    // Criar produtos de exemplo
    async createSampleProducts() {
        console.log('\n🥖 Criando produtos de exemplo...');
        
        const sampleProducts = [
            { name: 'Pão Francês', price: 0.50, category: 'Pães', description: 'Pão francês tradicional' },
            { name: 'Pão de Açúcar', price: 4.50, category: 'Pães', description: 'Pão doce com açúcar cristal' },
            { name: 'Brigadeiro', price: 2.00, category: 'Doces', description: 'Brigadeiro tradicional' },
            { name: 'Coxinha', price: 3.50, category: 'Salgados', description: 'Coxinha de frango' },
            { name: 'Café Expresso', price: 2.50, category: 'Bebidas', description: 'Café expresso forte' }
        ];

        for (const productData of sampleProducts) {
            try {
                await this.productController.createProduct(productData);
                await this.logger.success(`Produto criado: ${productData.name}`);
            } catch (error) {
                await this.logger.error(`Erro ao criar produto ${productData.name}`, { error: error.message });
            }
        }
    }

    // Demonstrar funcionalidades
    async demonstrateFeatures() {
        console.log('\n🎯 Demonstrando funcionalidades...');
        
        try {
            // Listar todos os produtos
            console.log('\n📋 Todos os produtos:');
            const allProducts = await this.productController.getAllProducts();
            allProducts.forEach(product => {
                console.log(`  • ${product.name} - R$ ${product.price.toFixed(2)} (${product.category})`);
            });

            // Listar todas as categorias
            console.log('\n📂 Todas as categorias:');
            const allCategories = await this.categoryController.getAllCategories();
            allCategories.forEach(category => {
                console.log(`  • ${category.name}: ${category.description}`);
            });

            // Buscar produtos por categoria
            console.log('\n🥖 Produtos da categoria "Pães":');
            const paes = await this.productController.getProductsByCategory('Pães');
            paes.forEach(product => {
                console.log(`  • ${product.name} - R$ ${product.price.toFixed(2)}`);
            });

            // Demonstrar atualização de produto
            if (allProducts.length > 0) {
                const firstProduct = allProducts[0];
                console.log(`\n✏️ Atualizando produto "${firstProduct.name}"...`);
                await this.productController.updateProduct(firstProduct.id, {
                    price: firstProduct.price + 0.10
                });
            }

            await this.logger.success('Demonstração concluída com sucesso');
            
        } catch (error) {
            await this.logger.error('Erro durante demonstração', { error: error.message });
            console.error('❌ Erro durante demonstração:', error.message);
        }
    }

    // Exibir menu interativo
    async showMenu() {
        console.log('\n🍞 ===== MENU DO SISTEMA =====');
        console.log('1. Listar todos os produtos');
        console.log('2. Listar todas as categorias');
        console.log('3. Buscar produtos por categoria');
        console.log('4. Criar novo produto');
        console.log('5. Criar nova categoria');
        console.log('6. Ver logs do sistema');
        console.log('0. Sair');
        console.log('================================');
    }
}

// Função principal
async function main() {
    const sistema = new PadariaSystem();
    await sistema.init();
    
    // Exibir menu
    await sistema.showMenu();
    
    console.log('\n🎉 Obrigado por usar o Sistema da Padaria!');
    console.log('💡 Para interação completa, implemente readline para menu interativo');
}

// Executar apenas se for o arquivo principal
if (require.main === module) {
    main().catch(error => {
        console.error('❌ Erro fatal:', error.message);
        process.exit(1);
    });
}

module.exports = PadariaSystem;

📝 Passo 6: Package.json

Vamos criar o arquivo de configuração do projeto:

📁 package.json

{
  "name": "sistema-padaria",
  "version": "1.0.0",
  "description": "Sistema completo para gerenciamento de padaria",
  "main": "app.js",
  "scripts": {
    "start": "node app.js",
    "dev": "node app.js",
    "test": "node test.js"
  },
  "keywords": [
    "padaria",
    "nodejs",
    "sistema",
    "gerenciamento"
  ],
  "author": "Aluno do Curso",
  "license": "MIT",
  "engines": {
    "node": ">=14.0.0"
  }
}

🚀 Passo 7: Instruções de Execução

📋 Como executar o projeto passo a passo:

  1. Abrir o terminal/prompt de comando
  2. Navegar até a pasta do projeto:
    cd sistema-padaria
  3. Verificar se o Node.js está instalado:
    node --version

    Deve mostrar a versão do Node.js (ex: v18.17.0)

  4. Executar o sistema:
    node app.js

    ou

    npm start

🧪 Passo 8: Teste Completo do Sistema

Vamos criar um arquivo de teste para verificar se tudo está funcionando:

📁 test.js

const PadariaSystem = require('./app');
const ProductController = require('./controllers/productController');
const CategoryController = require('./controllers/categoryController');
const Logger = require('./utils/logger');

async function runTests() {
    console.log('🧪 ===== EXECUTANDO TESTES =====');
    
    try {
        // Teste 1: Criar controllers
        console.log('\n✅ Teste 1: Criando controllers...');
        const productController = new ProductController();
        const categoryController = new CategoryController();
        const logger = new Logger();
        console.log('✅ Controllers criados com sucesso!');
        
        // Teste 2: Criar categoria
        console.log('\n✅ Teste 2: Criando categoria de teste...');
        const testCategory = await categoryController.createCategory({
            name: 'Teste',
            description: 'Categoria para testes'
        });
        console.log('✅ Categoria de teste criada!');
        
        // Teste 3: Criar produto
        console.log('\n✅ Teste 3: Criando produto de teste...');
        const testProduct = await productController.createProduct({
            name: 'Produto Teste',
            price: 5.99,
            category: 'Teste',
            description: 'Produto para testes'
        });
        console.log('✅ Produto de teste criado!');
        
        // Teste 4: Listar produtos
        console.log('\n✅ Teste 4: Listando produtos...');
        const products = await productController.getAllProducts();
        console.log(`✅ ${products.length} produtos encontrados!`);
        
        // Teste 5: Sistema completo
        console.log('\n✅ Teste 5: Testando sistema completo...');
        const sistema = new PadariaSystem();
        await sistema.init();
        console.log('✅ Sistema completo testado!');
        
        console.log('\n🎉 ===== TODOS OS TESTES PASSARAM! =====');
        console.log('✅ O sistema está funcionando perfeitamente!');
        console.log('🚀 Você pode executar: node app.js');
        
    } catch (error) {
        console.error('❌ Erro durante os testes:', error.message);
        console.error('🔧 Verifique se todos os arquivos foram criados corretamente');
    }
}

// Executar testes
if (require.main === module) {
    runTests();
}

module.exports = runTests;

🎯 Resumo do Exercício Completo:

  • ✅ Modelos: Product.js e Category.js (classes para organizar dados)
  • ✅ Utilitários: FileHelper.js (salvar/carregar arquivos JSON)
  • ✅ Controllers: ProductController.js e CategoryController.js (gerenciar operações)
  • ✅ Logs: Logger.js (registrar atividades do sistema)
  • ✅ App Principal: app.js (demonstração completa do sistema)
  • ✅ Configuração: package.json (configurações do projeto)
  • ✅ Testes: test.js (verificar se tudo funciona)
  • ✅ Instruções: Passo a passo para executar

🏆 Parabéns! Você criou um sistema completo de gerenciamento para padaria!

📚 Resumo da Aula

O que você aprendeu:

  • Sistema de módulos do Node.js
  • Diferenças entre CommonJS e ES6 modules
  • Manipulação de arquivos com fs
  • Trabalho com caminhos usando path

Próxima aula:

Aula 3: Introdução ao Express

Aprenda a criar seu primeiro servidor web com Express.js

Ir para próxima aula