graphql-lint-clint-platform
Version:
GraphQL unused fields linter for Clint platform - Custom patterns and actions.graphql support
228 lines • 9.52 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClintUsageAnalyzer = void 0;
const ts_morph_1 = require("ts-morph");
const parser_1 = require("@babel/parser");
const traverse_1 = __importDefault(require("@babel/traverse"));
const t = __importStar(require("@babel/types"));
class ClintUsageAnalyzer {
constructor() {
this.clintPatternUsages = new Map();
this.project = new ts_morph_1.Project({
useInMemoryFileSystem: true,
compilerOptions: {
allowJs: true,
allowSyntheticDefaultImports: true,
esModuleInterop: true,
},
});
}
/**
* Analisa uso de padrões Clint específicos: clint.entity.method
*/
async analyzeClintUsagePatterns(actionsQueries, fileContents) {
console.log(`🔍 Analisando padrões Clint para ${actionsQueries.length} actions em ${fileContents.size} arquivos`);
// Para cada action, procurar o padrão correspondente no código
for (const action of actionsQueries) {
const clintPattern = this.actionToClintPattern(action.name);
if (clintPattern) {
await this.findClintPatternUsages(clintPattern, action.name, fileContents);
}
}
return this.clintPatternUsages;
}
/**
* Procura usos de um padrão Clint específico no código
* Ex: clint.owner.getName
*/
async findClintPatternUsages(clintPattern, actionName, fileContents) {
for (const [filePath, content] of fileContents) {
if (filePath.includes('node_modules') || filePath.includes('.test.') || filePath.includes('.spec.')) {
continue;
}
try {
if (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {
await this.analyzeTypeScriptClintPattern(filePath, content, clintPattern, actionName);
}
else if (filePath.endsWith('.js') || filePath.endsWith('.jsx')) {
await this.analyzeJavaScriptClintPattern(filePath, content, clintPattern, actionName);
}
}
catch (error) {
console.warn(`⚠️ Erro ao analisar padrão Clint em ${filePath}:`, error);
}
}
}
/**
* Analisa padrões Clint em arquivos TypeScript
*/
async analyzeTypeScriptClintPattern(filePath, content, clintPattern, actionName) {
const sourceFile = this.project.createSourceFile(filePath, content, { overwrite: true });
// Procurar por member expressions que correspondem ao padrão Clint
// Ex: clint.owner.getName
sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.PropertyAccessExpression).forEach(propAccess => {
const fullText = propAccess.getText();
if (fullText === clintPattern) {
this.recordClintPatternUsage(actionName, {
file: filePath,
line: propAccess.getStartLineNumber(),
column: propAccess.getStart(),
pattern: clintPattern
});
}
});
// Procurar por call expressions do padrão
// Ex: clint.owner.getName() ou clint.owner.getName(id)
sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.CallExpression).forEach(callExpr => {
const expression = callExpr.getExpression();
if (ts_morph_1.Node.isPropertyAccessExpression(expression)) {
const fullText = expression.getText();
if (fullText === clintPattern) {
this.recordClintPatternUsage(actionName, {
file: filePath,
line: callExpr.getStartLineNumber(),
column: callExpr.getStart(),
pattern: `${clintPattern}()`
});
}
}
});
}
/**
* Analisa padrões Clint em arquivos JavaScript
*/
async analyzeJavaScriptClintPattern(filePath, content, clintPattern, actionName) {
try {
const ast = (0, parser_1.parse)(content, {
sourceType: "module",
allowImportExportEverywhere: true,
plugins: ["jsx", "typescript", "decorators-legacy"],
});
(0, traverse_1.default)(ast, {
MemberExpression: (path) => {
const memberChain = this.getMemberExpressionChain(path.node);
const fullPattern = memberChain.join('.');
if (fullPattern === clintPattern) {
this.recordClintPatternUsage(actionName, {
file: filePath,
line: path.node.loc?.start.line || 0,
column: path.node.loc?.start.column || 0,
pattern: clintPattern
});
}
},
CallExpression: (path) => {
if (t.isMemberExpression(path.node.callee)) {
const memberChain = this.getMemberExpressionChain(path.node.callee);
const fullPattern = memberChain.join('.');
if (fullPattern === clintPattern) {
this.recordClintPatternUsage(actionName, {
file: filePath,
line: path.node.loc?.start.line || 0,
column: path.node.loc?.start.column || 0,
pattern: `${clintPattern}()`
});
}
}
}
});
}
catch (error) {
console.warn(`⚠️ Erro ao parsear JavaScript para padrão Clint em ${filePath}:`, error);
}
}
/**
* Constrói cadeia de member expressions
* clint.owner.getName -> ['clint', 'owner', 'getName']
*/
getMemberExpressionChain(memberExpr) {
const chain = [];
let current = memberExpr;
while (t.isMemberExpression(current)) {
if (t.isIdentifier(current.property)) {
chain.unshift(current.property.name);
}
current = current.object;
}
if (t.isIdentifier(current)) {
chain.unshift(current.name);
}
return chain;
}
/**
* Registra uso de padrão Clint
*/
recordClintPatternUsage(actionName, usage) {
if (!this.clintPatternUsages.has(actionName)) {
this.clintPatternUsages.set(actionName, []);
}
this.clintPatternUsages.get(actionName).push(usage);
}
/**
* Converte nome de action para padrão Clint
* owner_get_name -> clint.owner.getName
*/
actionToClintPattern(actionName) {
const match = actionName.match(/^(\w+)_(.+)$/);
if (!match)
return null;
const [, entity, action] = match;
// Converter action para camelCase
const camelAction = action.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
return `clint.${entity}.${camelAction}`;
}
/**
* Retorna estatísticas de uso dos padrões Clint
*/
getUsageStats() {
const totalActions = this.clintPatternUsages.size;
const usedActions = Array.from(this.clintPatternUsages.values()).filter(usages => usages.length > 0).length;
const unusedActions = Array.from(this.clintPatternUsages.entries())
.filter(([, usages]) => usages.length === 0)
.map(([actionName]) => actionName);
return {
totalActions,
usedActions,
unusedActions,
usageDetails: this.clintPatternUsages
};
}
}
exports.ClintUsageAnalyzer = ClintUsageAnalyzer;
//# sourceMappingURL=clintAnalyzer-old.js.map