nodry
Version:
A CLI tool and Node.js library that warns about repetitive code to help you stay DRY.
68 lines (56 loc) • 2.19 kB
JavaScript
const fs = require('fs').promises;
const path = require('path');
async function analyze(filePath, options = {}) {
const {
lineThreshold = 3,
blockSize = 2,
blockThreshold = 2,
} = options;
const absolutePath = path.resolve(filePath);
try {
const content = await fs.readFile(absolutePath, 'utf-8');
// Remove block comments (/* ... */) and trim lines
const uncommented = content.replace(/\/\*[\s\S]*?\*\//g, '');
const linesRaw = uncommented.split('\n');
const lines = linesRaw
.map(l => l.trim())
.filter(l => l.length > 0 && !l.startsWith('//') && l !== '{' && l !== '}');
const lineCount = lines.reduce((acc, line) => {
acc[line] = (acc[line] || 0) + 1;
return acc;
}, {});
const repeatedLines = Object.entries(lineCount)
.filter(([, count]) => count >= lineThreshold);
const blocksCount = {};
for (let i = 0; i <= lines.length - blockSize; i++) {
const block = lines.slice(i, i + blockSize).join('\n');
blocksCount[block] = (blocksCount[block] || 0) + 1;
}
const repeatedBlocks = Object.entries(blocksCount)
.filter(([, count]) => count >= blockThreshold);
if (repeatedLines.length === 0 && repeatedBlocks.length === 0) {
console.log(`[nodry] ✅ No significant repetition found in ${filePath}.`);
return;
}
if (repeatedLines.length > 0) {
console.warn(`[nodry] ⚠️ Repeated lines detected in ${filePath}:`);
for (const [line, count] of repeatedLines) {
console.warn(`- "${line}" repeated ${count} times`);
}
}
if (repeatedBlocks.length > 0) {
console.warn(`[nodry] ⚠️ Repeated blocks of ${blockSize} lines detected in ${filePath}:`);
for (const [block, count] of repeatedBlocks) {
const preview = block.split('\n').map(l => l.trim()).join(' | ');
console.warn(`- Block repeated ${count} times: "${preview}"`);
}
}
} catch (err) {
if (err.code === 'ENOENT') {
console.error(`[nodry] ❌ File not found: ${absolutePath}`);
} else {
console.error(`[nodry] ❌ Error reading file: ${err.message}`);
}
}
}
module.exports = analyze;