File size: 3,098 Bytes
34367da
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0f01961
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import { config } from 'dotenv';
import { resolve } from 'path';
import { fileURLToPath } from 'url';
import { writeFileSync } from 'fs';
import neo4j from 'neo4j-driver';

const __dirname = fileURLToPath(new URL('.', import.meta.url));
config({ path: resolve(__dirname, '../../.env') });

const NEO4J_URI = process.env.NEO4J_URI || 'bolt://localhost:7687';
const NEO4J_USERNAME = process.env.NEO4J_USERNAME || 'neo4j';
const NEO4J_PASSWORD = process.env.NEO4J_PASSWORD || 'password';

async function huntZombies() {
    console.log('🧟 Operation Zombie Hunter starting...');
    const driver = neo4j.driver(NEO4J_URI, neo4j.auth.basic(NEO4J_USERNAME, NEO4J_PASSWORD));
    const session = driver.session();

    try {
        const result = await session.run(`

            MATCH (f:File)

            WHERE (f.language = 'TypeScript' OR f.extension = '.ts' OR f.extension = '.tsx')

              AND NOT ()-[:DEPENDS_ON]->(f)

              AND NOT f.name ENDS WITH '.test.ts'

              AND NOT f.name ENDS WITH '.spec.ts'

              AND NOT f.name = 'index.ts'

              AND NOT f.name = 'main.tsx'

              AND NOT f.name = 'App.tsx'

              AND NOT f.name STARTS WITH 'vite'

              AND NOT f.name STARTS WITH 'eslint'

              AND NOT f.name STARTS WITH 'playwright'

              AND NOT f.name STARTS WITH 'vitest'

              AND NOT f.relativePath CONTAINS 'scripts'

              AND NOT f.relativePath CONTAINS 'tests'

              AND NOT f.relativePath CONTAINS 'config'

            RETURN f.relativePath as path, f.name as name, f.size as size

            ORDER BY f.relativePath

        `);

        const zombies = result.records.map(r => {
            const s = r.get('size');
            const size = neo4j.isInt(s) ? s.toNumber() : Number(s);
            return {
                path: r.get('path'),
                name: r.get('name'),
                size: isNaN(size) ? 0 : size
            };
        });

        console.log(`Found ${zombies.length} potential zombie files.`);

        let report = '# 🧟 Zombie Code Report\n\n';
        report += `**Date:** ${new Date().toISOString()}\n`;
        report += `**Total Potential Zombies:** ${zombies.length}\n\n`;
        report += '> These files are not imported by any other TypeScript file in the project (based on static analysis).\n';
        report += '> **Verify manually** before deleting.\n\n';
        report += '| File Path | Size (Bytes) |\n';
        report += '|-----------|--------------|\n';

        for (const z of zombies) {
            report += '| `' + z.path + '` | ' + z.size + ' |\n';
        }

        const reportPath = resolve(__dirname, '../../../../docs/ZOMBIE_CODE_REPORT.md');
        writeFileSync(reportPath, report);
        console.log(`📝 Report generated at: ${reportPath}`);

    } catch (error: any) {
        console.error('❌ Zombie Hunter failed:', error.message);
    } finally {
        await session.close();
        await driver.close();
    }
}

huntZombies();