Tuesday, January 21, 2025

surveying eslint-disables across a code base

An architect was mentioning some counts of eslint-disables in our code base, and I wanted to take a closer look.

(I know different devs have different intuitions about the criticality of some of these rules: I know for me, if there's a trade off between "concise, more readable code that keeps attention to what's actually new" vs "well-enforced lint standards and rigorously enforced strong typing at every level that MIGHT help turn a runtime error into a buildtime problem", I lean towards the former.)

I started by recursive grepping for those lines, and putting them into a .txt file so future steps would be faster:

grep -r "eslint-disable" | grep -v node_modules/   >  ~/raw.txt

I then used CoPilot to come up with a node.js script to break up the lines and do counts by subproject in the monorepo:)

const fs = require('fs');
const readline = require('readline');

// Create a read stream for raw.txt
const fileStream = fs.createReadStream('raw.txt');

// Create an interface to read the file line by line
const rl = readline.createInterface({
  input: fileStream,
  crlfDelay: Infinity
});

// Initialize the counts and totalCounts objects
const counts = {};
const totalCounts = {};

// Process each line
rl.on('line', (line) => {
  // Split the line on whitespace
  const sections = line.split(/\s+/);

  const regex = /\.\/([^\/]+\/[^\/]+)\//;
  const match = sections[0].match(regex);

  if (!match) {
    console.log(`NO MATCH FOR ${line}\n`);
    return;
  }

  const appOrLib = match[1];

  const offset = sections.findIndex(section => section.startsWith('eslint-disable'));

  if (offset === -1) {
    console.log(`NO MATCH FOR ${line}\n`);
  } else {
    // Join the remaining parts on " ", ignoring "*/"
    const remainingParts = sections.slice(offset + 1).filter(part => part !== '*/');
    const joinedParts = remainingParts.join(' ');

    // Split each remaining part on "," and treat them separately
    const finalParts = joinedParts.split(',').map(part => part.trim());

    // Initialize the appOrLib object if it doesn't exist
    if (!counts[appOrLib]) {
      counts[appOrLib] = {};
      totalCounts[appOrLib] = 0;
    }

    finalParts.forEach(part => {
      const key = part || '[EMPTY]';
      if (!counts[appOrLib][key]) {
        counts[appOrLib][key] = 0;
      }
      counts[appOrLib][key]++;
      totalCounts[appOrLib]++;
    });
  }
});

// Print the counts object when done
rl.on('close', () => {
  for (const appOrLib in counts) {
    console.log(`${appOrLib}: ${totalCounts[appOrLib]}`);
    const sortedKeys = Object.keys(counts[appOrLib]).sort((a, b) => counts[appOrLib][b] - counts[appOrLib][a]);
    sortedKeys.forEach(key => {
      console.log(`\t${key}: ${counts[appOrLib][key]}`);
    });
  }
});

No comments:

Post a Comment