graphql-lint-clint-platform
Version:
GraphQL unused fields linter for Clint platform - Custom patterns and actions.graphql support
137 lines (108 loc) • 5.88 kB
text/typescript
import { Command } from "commander";
import path from "path";
import { ClintGraphQLExtractor, ClintAction } from "./clintExtractor";
import { ClintUsageAnalyzer, ClintUsageResult } from "./clintAnalyzer";
const program = new Command();
program
.name("graphql-lint-clint")
.description("🎯 Ferramenta específica da Clint para análise de actions GraphQL do Hasura")
.version("1.0.0")
.argument("[paths...]", "Caminhos dos arquivos ou diretórios para analisar", ["."])
.option("-i, --include <patterns...>", "Padrões de arquivos para incluir", ["**/*.{ts,tsx,js,jsx}", "**/actions.graphql"])
.option("-e, --exclude <patterns...>", "Padrões de arquivos para excluir", ["node_modules/**", "dist/**", "build/**"])
.option("-f, --format <format>", "Formato de saída (console, json)", "console")
.option("-o, --output <file>", "Arquivo de saída (se não especificado, usa stdout)")
.option("--verbose", "Modo verboso")
.action(async (paths: string[], options) => {
try {
console.log("🎯 CLINT GRAPHQL LINT - HASURA ACTIONS ANALYZER\n");
if (options.verbose) {
console.log("📋 Configuração:");
console.log(` 🎯 Caminhos: ${paths.join(", ")}`);
console.log(` 📁 Incluir: ${options.include.join(", ")}`);
console.log(` 🚫 Excluir: ${options.exclude.join(", ")}`);
console.log("");
}
// 1. Extrair actions do Hasura
console.log("🔍 Extraindo actions do Hasura...");
const extractor = new ClintGraphQLExtractor();
const actions: ClintAction[] = [];
for (const targetPath of paths) {
const absolutePath = path.resolve(targetPath);
await extractor.extractFromPath(absolutePath, actions, options.include, options.exclude);
}
const actionPatterns = extractor.getActionPatterns();
const totalActions = Object.keys(actionPatterns).length;
console.log(` ✅ ${totalActions} actions encontradas\n`);
// 2. Analisar uso das actions no código
console.log("🔍 Analisando uso das actions no código...");
const analyzer = new ClintUsageAnalyzer(actionPatterns);
const sourcePath = paths[0] ? path.resolve(paths[0]) : process.cwd();
const result = await analyzer.analyzeUsageInPath(sourcePath, options.verbose);
// 3. Reportar resultados
console.log("📊 RESULTADOS DA ANÁLISE CLINT:");
console.log("".padEnd(50, "="));
const usedActions = Object.keys(result.usedActions).length;
const unusedActions = result.unusedActions.length;
console.log(`🎯 Actions analisadas: ${totalActions}`);
console.log(`✅ Actions em uso: ${usedActions} (${Math.round((usedActions/totalActions)*100)}%)`);
console.log(`❌ Actions não utilizadas: ${unusedActions} (${Math.round((unusedActions/totalActions)*100)}%)`);
if (unusedActions > 0) {
console.log("\n🚨 ACTIONS NÃO UTILIZADAS (NECESSITAM OTIMIZAÇÃO):");
console.log("".padEnd(60, "="));
result.unusedActions.forEach(actionName => {
// Usar códigos ANSI para cor vermelha
const redText = `\x1b[31m❌ ${actionName}\x1b[0m`;
const patternText = `\x1b[33m→ Padrões: ${actionPatterns[actionName].join(', ')}\x1b[0m`;
console.log(` ${redText}`);
console.log(` 🔗 ${patternText}`);
console.log("");
});
console.log("".padEnd(60, "="));
console.log(`\x1b[31m⚠️ TOTAL DE ACTIONS DESPERDIÇADAS: ${unusedActions}\x1b[0m`);
console.log(`\x1b[33m💡 Remova ou implemente o uso dessas actions para otimizar o projeto!\x1b[0m`);
}
if (options.format === "json") {
const jsonOutput = {
summary: {
total: totalActions,
used: usedActions,
unused: unusedActions,
usagePercentage: Math.round((usedActions/totalActions)*100)
},
result: result
};
if (options.output) {
const fs = await import("fs");
fs.writeFileSync(options.output, JSON.stringify(jsonOutput, null, 2));
console.log(`\n📁 Resultado salvo em: ${options.output}`);
} else {
console.log("\n📄 JSON OUTPUT:");
console.log(JSON.stringify(jsonOutput, null, 2));
}
}
console.log("\n🎯 Análise Clint concluída!");
// NOVA FUNCIONALIDADE: Throw error se houver actions não utilizadas
if (unusedActions > 0) {
console.log(`\n\x1b[31m💥 ERRO: Encontradas ${unusedActions} actions não utilizadas!\x1b[0m`);
console.log(`\x1b[33m🔧 AÇÃO NECESSÁRIA: Otimize as seguintes queries removendo ou implementando seu uso:\x1b[0m`);
// Lista resumida para o erro
result.unusedActions.forEach(actionName => {
console.log(`\x1b[31m • ${actionName} → ${actionPatterns[actionName].join(', ')}\x1b[0m`);
});
console.log(`\n\x1b[37m📖 DICA: Execute novamente após implementar o uso ou remover as actions desnecessárias.\x1b[0m`);
// Throw com informações detalhadas
const errorMessage = `🚨 OTIMIZAÇÃO NECESSÁRIA: ${unusedActions} actions da Clint não estão sendo utilizadas no código. ` +
`Actions desperdiçadas: ${result.unusedActions.join(', ')}. ` +
`Implemente o uso ou remova essas actions para otimizar o projeto.`;
throw new Error(errorMessage);
}
// Exit com sucesso se não houver actions não utilizadas
console.log("\n\x1b[32m✅ Todas as actions estão sendo utilizadas corretamente!\x1b[0m");
} catch (error) {
console.error("❌ Erro na análise:", error);
process.exit(1);
}
});
program.parse();