eslint-rules/scripts/check-imports.ts
2024-01-13 18:20:36 -05:00

70 lines
1.9 KiB
TypeScript
Executable File

#!/usr/bin/env bun
import glob from 'fast-glob';
import fs from 'fs';
import { builtinModules } from 'module';
import { uniq } from 'lodash';
import { dependencies, peerDependencies, overrides } from '../dist/package.json';
function checkImports() {
const deps = Object.keys({ ...dependencies, ...peerDependencies, ...overrides }).concat(
'eslint',
);
const builtIn = new Set(builtinModules.flatMap(module => [module, `node:${module}`]));
function findRequires(text: string) {
const list = Array.from(text.matchAll(/require\(["']([^"']+)["']\)/g))
.map(m => m[1])
.filter(
module =>
!(
builtIn.has(module) ||
module.startsWith('eslint/') ||
module.startsWith('typescript/')
),
);
return uniq(list);
}
const moduleMap = glob
.sync(['dist/**/*.js', '!dist/node_modules/**'])
.map(path => ({ key: path, value: findRequires(fs.readFileSync(path, 'utf8')) }));
const files = Object.fromEntries(
moduleMap
.map(({ key, value }) => ({
key,
value: value.filter(
module =>
!(deps.includes(module) || deps.some(dep => module.startsWith(`${dep}/`))),
),
}))
.filter(({ value }) => value.length > 0)
.map(({ key, value }) => [key, value]),
);
const uselessDeps = Object.keys(dependencies).filter(
dep => !moduleMap.some(({ value }) => value.includes(dep)),
);
return {
missingImports: files,
unusedDependencies: uselessDeps,
};
}
function checkDeps() {
const pkgJson = glob
.sync(['dist/node_modules/@*/*/package.json', 'dist/node_modules/*/package.json'])
.sort()
.map(path => fs.readFileSync(path, 'utf8'))
.map(content => JSON.parse(content))
.filter(({ author }) => JSON.stringify(author ?? 'null').includes('ljharb'))
.map(({ name }) => name);
return { suspiciousPackages: pkgJson };
}
console.log({
...checkImports(),
...checkDeps(),
});