npm package: @opens/docgen
Description: A library for generating documents in various formats such as PDF, Excel, and CSV.
Author: Opens Tecnologia
Latest version: 0.0.2

# Docgen

Uma biblioteca TypeScript para geração de documentos em vários formatos como PDF, Excel e CSV.

[![MIT License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

## Instalação

```bash
npm install @opens/docgen
```

ou

```bash
yarn add @opens/docgen
```

## Recursos

- Geração de documentos em formatos:
  - PDF
  - Excel
  - CSV
- Criação de tabelas com dados estruturados
- Customização de estilo e formatação
- Suporte para streaming para processamento eficiente de grandes volumes de dados
- Integração com serviços de armazenamento como Amazon S3

## Como Usar

### Importação

```typescript
import { 
  DocumentGenerator, 
  DocumentTable, 
  DocumentFormat 
} from '@opens/docgen';
```

### Exemplo Básico

```typescript
import { createWriteStream } from 'fs';
import { 
  DocumentGenerator, 
  DocumentTable, 
  DocumentFormat,
  ColumnDefinition
} from '@opens/docgen';

// Função geradora que produz os elementos do documento
function* relatorioVendasGenerator() {
  // Definição das colunas para nossa tabela
  const columns: ColumnDefinition[] = [
    { field: 'produto', header: 'Produto' },
    { field: 'quantidade', header: 'Quantidade' },
    { field: 'valorUnitario', header: 'Valor Unitário (R$)' },
    { field: 'valorTotal', header: 'Valor Total (R$)' },
    { field: 'data', header: 'Data da Venda' }
  ];

  // Dados de exemplo para a tabela
  const dadosVendas = [
    { 
      produto: 'Notebook Dell XPS 13', 
      quantidade: 5, 
      valorUnitario: 8500.00, 
      valorTotal: 42500.00, 
      data: '15/01/2025'
    },
    { 
      produto: 'Monitor LG Ultrawide', 
      quantidade: 8, 
      valorUnitario: 2200.00, 
      valorTotal: 17600.00, 
      data: '22/01/2025'
    },
    { 
      produto: 'Teclado Mecânico Logitech', 
      quantidade: 12, 
      valorUnitario: 450.00, 
      valorTotal: 5400.00, 
      data: '07/02/2025'
    },
    { 
      produto: 'Mouse sem fio Logitech', 
      quantidade: 15, 
      valorUnitario: 180.00, 
      valorTotal: 2700.00, 
      data: '14/02/2025'
    },
    { 
      produto: 'Headset HyperX', 
      quantidade: 10, 
      valorUnitario: 350.00, 
      valorTotal: 3500.00, 
      data: '28/02/2025'
    }
  ];

  // Criação do elemento de tabela com os dados e configurações
  const tabelaVendas = new DocumentTable({
    columns,
    data: dadosVendas,
    header: true,
    title: 'Vendas do Primeiro Trimestre de 2025',
    footer: 'Relatório gerado automaticamente em ' + new Date().toLocaleDateString('pt-BR')
  });

  // Retorna o elemento para o gerador de documentos
  yield tabelaVendas;
}

// Função principal para gerar o relatório
async function gerarRelatorioDeVendas() {
  try {
    // Cria um stream para o arquivo de saída
    const outputStream = createWriteStream('./relatorio-vendas.pdf');

    // Configura o formato do documento
    const config = {
      format: DocumentFormat.PDF,
    };

    // Instancia o gerador de documentos
    const generator = new DocumentGenerator(config, outputStream);

    // Gera o documento utilizando nossa função geradora
    await generator.generate(relatorioVendasGenerator);

    console.log('Relatório de vendas gerado com sucesso!');
  } catch (error) {
    console.error('Erro ao gerar relatório:', error);
  }
}
```

### Integração com Amazon S3

#### Enviando documentos diretamente para o S3

```typescript
import { PassThrough } from 'stream';
import { S3Client, Upload } from '@aws-sdk/client-s3';
import { 
  DocumentGenerator, 
  DocumentTable, 
  DocumentFormat
} from '@opens/docgen';

function* relatorioFuncionariosGenerator() {
  // Definir colunas e dados
  const columns = [
    { field: 'nome', header: 'Nome' },
    { field: 'departamento', header: 'Departamento' },
    { field: 'cargo', header: 'Cargo' }
  ];

  const funcionarios = [
    { nome: 'Ana Silva', departamento: 'Vendas', cargo: 'Gerente Regional' },
    { nome: 'Carlos Mendes', departamento: 'TI', cargo: 'Desenvolvedor Sênior' },
    { nome: 'Juliana Costa', departamento: 'Marketing', cargo: 'Analista de Mídias Sociais' }
  ];

  // Criar tabela
  const tabela = new DocumentTable({
    columns,
    data: funcionarios,
    header: true,
    title: 'Relatório de Funcionários',
    footer: 'Gerado em ' + new Date().toLocaleDateString('pt-BR')
  });

  yield tabela;
}

async function gerarEEnviarParaS3() {
  try {
    // Configuração do cliente S3
    const s3Client = new S3Client({
      region: 'sa-east-1',
      credentials: {
        accessKeyId: process.env.AWS_ACCESS_KEY_ID || '',
        secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || ''
      }
    });

    // Criação de um stream de passagem (passthrough)
    const passThrough = new PassThrough();

    // Configurar o upload para o S3 (iniciará automaticamente quando dados forem escritos)
    const uploadParams = {
      Bucket: 'minha-empresa-relatorios',
      Key: `relatorio-funcionarios-${Date.now()}.pdf`,
      Body: passThrough,
      ContentType: 'application/pdf'
    };

    // Iniciar o upload
    const uploadPromise = new Upload({
      client: s3Client,
      params: uploadParams
    }).done();

    // Configurar o gerador de documentos com o stream de passagem
    const generator = new DocumentGenerator({
      format: DocumentFormat.PDF,
      options: {
        orientation: 'portrait',
        title: 'Relatório para S3'
      }
    }, passThrough);

    // Gerar documento (os dados fluirão automaticamente para o S3 via passthrough)
    await generator.generate(relatorioFuncionariosGenerator);

    // Aguardar até que o upload seja concluído
    const uploadResult = await uploadPromise;
    console.log('Documento enviado com sucesso para o S3:', uploadResult);
    return uploadResult;
  } catch (error) {
    console.error('Erro ao enviar para o S3:', error);
    throw error;
  }
}
```

### Geração de Diferentes Formatos

#### PDF

```typescript
const pdfConfig = {
  format: DocumentFormat.PDF,
  options: {
    orientation: 'portrait'
  }
};
```

#### Excel

```typescript
const excelConfig = {
  format: DocumentFormat.EXCEL,
  options: {
    sheetName: 'Dados',
  }
};
```

#### CSV

```typescript
const csvConfig = {
  format: DocumentFormat.CSV,
  options: {
    filename: 'relatorio.csv'
  }
};
```

### Parâmetro Header nas Tabelas

O parâmetro `header` nas tabelas é utilizado para controlar a exibição do cabeçalho:

```typescript
// Com cabeçalho (default)
const tableWithHeader = new DocumentTable({
  columns,
  data,
  header: true // Irá incluir o cabeçalho da tabela
});

// Sem cabeçalho - útil quando adicionando múltiplas tabelas que formam uma só
const tableWithoutHeader = new DocumentTable({
  columns,
  data,
  header: false // Não incluirá o cabeçalho, apenas os dados
});
```

Quando utilizado como `false`, o cabeçalho da tabela não será incluído, o que é útil em cenários onde:
- Você está adicionando múltiplas tabelas que representam partes de uma mesma tabela lógica
- Você deseja adicionar dados a uma tabela existente sem repetir o cabeçalho

### Trabalhando com Streaming

Para arquivos grandes ou geração sob demanda:

```typescript
import { createWriteStream } from 'fs';
import { DocumentGenerator, DocumentTable, DocumentFormat } from '@opens/docgen';

async function* relatorioStreamingGenerator() {
  // Definição de colunas
  const yourColumns = [
    { field: 'id', header: 'ID' },
    { field: 'nome', header: 'Nome' },
    { field: 'valor', header: 'Valor (R$)' },
    { field: 'data', header: 'Data de Registro' }
  ];
  
  // Simulação de busca de dados em lotes
  const batchSize = 100;
  for (let i = 0; i < 1000; i += batchSize) {
    const rows = await fetchDataBatch(i, batchSize); // Função fictícia para buscar dados
    
    // Primeira parte com cabeçalho
    if (i === 0) {
      const tableWithHeader = new DocumentTable({
        columns: yourColumns,
        data: rows,
        header: true, // Primeira parte inclui cabeçalho
        title: 'Relatório de Dados em Streaming',
      });
      yield tableWithHeader;
    } else {
      // Partes subsequentes sem cabeçalho
      const tableWithoutHeader = new DocumentTable({
        columns: yourColumns,
        data: rows,
        header: false // Partes subsequentes não incluem cabeçalho
      });
      yield tableWithoutHeader;
    }
  }
}

async function gerarRelatorioStreaming() {
  try {
    const outputStream = createWriteStream('./relatorio-streaming.pdf');
    
    const generator = new DocumentGenerator({
      format: DocumentFormat.PDF,
      options: {
        orientation: 'landscape',
        title: 'Relatório de Dados em Lotes'
      }
    }, outputStream);
    
    await generator.generate(relatorioStreamingGenerator);
    
    console.log('Relatório em streaming gerado com sucesso!');
  } catch (error) {
    console.error('Erro ao gerar relatório em streaming:', error);
  }
}
```

## Tipos Disponíveis

A biblioteca exporta vários tipos úteis:

```typescript
import {
  // Tipos principais
  ColumnDefinition,
  DocumentConfiguration,
  BaseElement,
  ElementType,
  DocumentFormat,
  
  // Tipos para estilos
  ElementStyling,
  TextAlignment,
  PageOrientation,
  
  // Configurações específicas para formatos
  PDFDocumentSettings,
  ExcelDocumentSettings,
  CSVDocumentSettings,
  
  // Tipos para elementos específicos
  PDFTableElementData,
  ExcelTableElementData,
  CSVTableElementData,
} from '@opens/docgen';
```

### Estrutura de ColumnDefinition

```typescript
interface ColumnDefinition {
  field: string;    // A chave do campo nos dados
  header: string;   // O texto que aparecerá no cabeçalho
  width?: number;   // Largura opcional da coluna
}
```

### Configurações por formato

```typescript
// Configurações para PDF
interface PDFDocumentSettings {
  orientation?: PageOrientation; // 'portrait' ou 'landscape'
  title?: string;               // Título do documento
  subtitle?: string;            // Subtítulo do documento
}

// Configurações para Excel
interface ExcelDocumentSettings {
  sheetName?: string;           // Nome da planilha
}

// Configurações para CSV
interface CSVDocumentSettings {
  delimiter?: string;           // Caractere delimitador
}
```

## Licença

Este projeto está licenciado sob a licença MIT - veja o arquivo LICENSE para mais detalhes.

## Contribuições

Contribuições são bem-vindas! Sinta-se à vontade para abrir issues ou pull requests.