PRININIT / lib /src /dedup.js
Rachit-Tw's picture
Upload 199 files
cbc1ce0 verified
Raw
History Blame Contribute Delete
4.03 kB
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isDuplicateIssue = isDuplicateIssue;
exports.registerIssue = registerIssue;
exports.clearDedupCache = clearDedupCache;
exports.getDedupStats = getDedupStats;
exports.cleanupDedupCache = cleanupDedupCache;
function simpleHash(str) {
let hash = 0x811c9dc5;
for (let i = 0; i < str.length; i++) {
hash ^= str.charCodeAt(i);
hash = Math.imul(hash, 0x01000193);
}
return (hash >>> 0).toString(16).padStart(8, '0');
}
function normalizePath(path) {
return path
.toLowerCase()
.replace(/\\/g, '/')
.replace(/^\.\//, '')
.replace(/\/index\.(ts|tsx|js|jsx)$/, '');
}
function normalizeType(type) {
const typeMap = {
mutation: 'mutation',
mutating: 'mutation',
mutate: 'mutation',
async: 'async',
race: 'async',
promise: 'async',
'null-safety': 'null-safety',
null: 'null-safety',
undefined: 'null-safety',
security: 'security',
vulnerability: 'security',
performance: 'performance',
slow: 'performance',
syntax: 'syntax',
error: 'syntax',
bug: 'bug',
logic: 'bug'
};
return typeMap[type.toLowerCase()] || type.toLowerCase();
}
function normalizeLineRange(start, end) {
return `${Math.floor(start / 5) * 5}-${Math.ceil(end / 5) * 5}`;
}
function normalizeForDedup(description) {
return description
.toLowerCase()
.replace(/[^\w\s-]/g, ' ')
.replace(/\s+/g, ' ')
.trim();
}
function extractSemanticKey(description, type) {
const normalized = description
.toLowerCase()
.replace(/\b(may|might|could|possible|possibly|perhaps|maybe|seems|appears|probably|usually|generally|mostly|sometimes|often)\b/g, '')
.replace(/\b(the|a|an|is|are|was|were|be|been|being|there|this|that|these|those|in|on|at|for|with|by|from|to|of|it|its|their|them|they|not|will|would|should|can|could|have|has|had|what|which|who|when|where|how|also|very|just|some|any|each|every|both|such)\b/g, '')
.replace(/[^\w\s-]/g, ' ')
.replace(/\s+/g, ' ')
.trim();
const words = normalized.split(' ').filter(w => w.length > 3);
const keyTerms = words.slice(0, 5).join(' ');
return `${normalizeType(type)}:${keyTerms}`;
}
function generateSemanticHash(path, type, startLine, endLine, description) {
const sig = JSON.stringify({
path: normalizePath(path),
type: normalizeType(type),
range: normalizeLineRange(startLine, endLine),
key: normalizeForDedup(description)
});
return simpleHash(sig);
}
class DedupCache {
store = new Map();
async isDuplicate(key) {
return this.store.has(`dedup:${key}`);
}
async add(key) {
this.store.set(`dedup:${key}`, '1');
}
async clear() {
this.store.clear();
}
async size() {
return this.store.size;
}
async cleanup() {
this.store.clear();
}
}
const dedupCache = new DedupCache();
async function isDuplicateIssue(path, type, startLine, endLine, description) {
const hash = generateSemanticHash(path, type, startLine, endLine, description);
if (await dedupCache.isDuplicate(hash))
return true;
const semKey = simpleHash(extractSemanticKey(description, type));
if (await dedupCache.isDuplicate(`semantic:${semKey}`))
return true;
return false;
}
async function registerIssue(path, type, startLine, endLine, description) {
const hash = generateSemanticHash(path, type, startLine, endLine, description);
await dedupCache.add(hash);
await dedupCache.add(`semantic:${simpleHash(extractSemanticKey(description, type))}`);
}
async function clearDedupCache() {
await dedupCache.clear();
}
async function getDedupStats() {
return { size: await dedupCache.size() };
}
async function cleanupDedupCache() {
await dedupCache.cleanup();
}
//# sourceMappingURL=dedup.js.map