@donatocardoso/busca-cli
Version:
Ferramenta responsável por ler o conteúdo de arquivos e filtrá-los de acordo com um texto informado
154 lines (129 loc) • 5.92 kB
JavaScript
const { Command, Option } = require('commander');
const fs = require('fs');
const path = require('path');
const readline = require('readline');
const { mostraMensagem } = require('../../utils/message');
const input = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false,
});
/**
* Cria o comando `carregar`, que realiza uma busca em um ou mais caminhos
* @param {Command} programa
* @returns Command
*/
module.exports = () => {
return new Command('carregar')
.usage('[opcoes] -c [caminhos...]')
.description('Carrega em memória os arquivos do diretório informado', {
caminho: 'Diretório em que a busca será realizada',
texto: 'Texto de busca nos arquivos',
})
.requiredOption('-c, --caminhos [caminhos...]', 'Arquivo(s) em que a verificação será realizada')
.addOption(new Option('-d, --detalhes', 'Retorna detalhes dos arquivos encontrados'))
.addOption(new Option('-e, --exato', 'Busca pela sentença exata informada'))
.addOption(new Option('-r, --recursivo', 'Busca na pasta e sub-pastas do caminho informado'))
.addOption(new Option('-s, --sensivel', 'Diferencia maiúscula de minúscula'))
.helpOption('-a, --ajuda', 'Exibi ajuda para usar o comando')
.addHelpText('afterAll', '\nExemplos de chamada:\n')
.addHelpText('afterAll', '')
.addHelpText('afterAll', '$ busca-cli carregar -c ./pasta01 ./pasta02 ./arquivo01.txt ./arquivo02.txt')
.addHelpText('afterAll', '$ busca-cli carregar -ders -c ./pasta01 ./pasta02 ./arquivo01.txt ./arquivo02.txt')
.addHelpText('afterAll', '$ busca-cli carregar -d -e -r -s -c ./pasta01 ./pasta02 ./arquivo01.txt ./arquivo02.txt')
.action(carregar);
};
/**
* Carregar arquivos em memoria e realiza um filtro comforme texto informado
* @param {object} options Opções para carregar os arquivos
* @param {string[]} options.caminhos Caminhos em que a busca será realizada
* @param {boolean} options.detalhes Deseja uma busca detalhada
* @param {boolean} options.exato Deseja uma busca pela sentença exata
* @param {boolean} options.recursivo Deseja uma busca na pasta e sub-pastas
* @param {boolean} options.sensivel Deseja uma busca que diferencie maiúscula de minúscula
*/
function carregar(options) {
const tempoCarregar = new Date().getTime();
const carregados = [];
const naoEncontrados = [];
const opcoesProps = Object.getOwnPropertyNames(options).sort();
options.caminhos.forEach(function _busca(caminho) {
const caminhoCompleto = path.resolve(process.cwd(), caminho);
if (!fs.existsSync(caminhoCompleto)) return naoEncontrados.push(caminhoCompleto);
if (fs.statSync(caminhoCompleto).isDirectory()) {
// Pasta informada via paramentro, ou seja, pasta raiz
fs.readdirSync(caminhoCompleto).forEach((arquivo) => {
// Verificação para realizar recursividade
if (fs.statSync(`${caminhoCompleto}/${arquivo}`).isDirectory()) {
if (options.recursivo) return _busca(`${caminhoCompleto}/${arquivo}`);
return;
}
const conteudo = fs.readFileSync(`${caminhoCompleto}/${arquivo}`, {
encoding: 'utf8',
});
const propriedades = fs.statSync(`${caminhoCompleto}/${arquivo}`);
carregados.push({
palavras: conteudo.split(' ').filter((word) => !!word).length,
elementos: conteudo.length,
tamanho: `${propriedades.size} bytes`,
caminho: `${caminhoCompleto}/${arquivo}`,
conteudo,
});
});
} else {
const conteudo = fs.readFileSync(caminhoCompleto, {
encoding: 'utf8',
});
const propriedades = fs.statSync(caminhoCompleto);
carregados.push({
palavras: conteudo.split(' ').filter((word) => !!word).length,
elementos: conteudo.length,
tamanho: `${propriedades.size} bytes`,
caminho: caminhoCompleto,
conteudo,
});
}
});
mostraMensagem(
'Caminhos.........................:',
...options.caminhos.map((caminho) => ` |__ ........................: ${caminho}`),
'',
`Opções...........................: ${opcoesProps}`,
...(naoEncontrados.length ? ['', 'Os caminhos a seguir não foram encontrados:', '', ...naoEncontrados, ''] : ['']),
`Tempo de processamento...........: ${new Date().getTime() - tempoCarregar}ms`,
`Foram carregados.................: ${carregados.length} arquivos!`
);
input.question('\nInforme o texto que deseja buscar: ', (texto) => {
const tempoFiltrar = new Date().getTime();
const palavras = texto.split(' ');
const sensivel = options.sensivel ? 'g' : 'ig';
const pattern = options.exato ? `(\\b${texto}\\b)` : `${palavras.map((word) => `(\\b${word}\\b)`).join('|')}`;
const regex = new RegExp(pattern, sensivel);
const encontrados = carregados.filter((arquivo) => {
const encontros = arquivo.conteudo.match(regex);
const encontrosUnicos = Array.from(new Set(encontros));
delete arquivo.conteudo;
return (
encontrosUnicos &&
((options.exato && encontrosUnicos.length) || (palavras && encontrosUnicos.length === palavras.length))
);
});
mostraMensagem(
'',
`Foram encontradas ${encontrados.length} ocorrências pelo termo "${texto}"`,
...(encontrados.length
? [
`Os arquivos que possuem "${texto}" são:`,
'',
...(options.detalhes ? encontrados : encontrados.map((arquivo) => arquivo.caminho)),
'',
]
: ['', 'Nenhum arquivo encontrado!', '']),
`Tempo de processamento...........: ${new Date().getTime() - tempoFiltrar}ms`,
`Foram encontrados................: ${encontrados.length} arquivos!`
);
input.close();
/* istanbul ignore next */
if (process.env.NODE_ENV !== 'test') process.exit();
});
}