From 566b4c0042992a72cea468488f18ed49082f6226 Mon Sep 17 00:00:00 2001 From: George Fu Date: Wed, 7 Aug 2024 11:17:47 -0400 Subject: [PATCH] chore(scripts): discover unused packages (#6364) --- scripts/validation/deprecated-packages.js | 105 +++++++++++++++++----- 1 file changed, 85 insertions(+), 20 deletions(-) diff --git a/scripts/validation/deprecated-packages.js b/scripts/validation/deprecated-packages.js index a0ba956e02ca9..956d3cc23dfb4 100644 --- a/scripts/validation/deprecated-packages.js +++ b/scripts/validation/deprecated-packages.js @@ -1,33 +1,98 @@ const fs = require("node:fs"); -const fse = require("fs-extra"); const path = require("node:path"); const root = path.join(__dirname, "..", ".."); const packages = path.join(root, "packages"); +const libs = path.join(root, "lib"); +const clients = path.join(root, "clients"); -const excluded = []; +/** + * Throw and Error if any deprecated package is not marked private. + */ +{ + const excluded = []; -for (const folder of fs.readdirSync(packages)) { - const pkgJson = require(path.join(packages, folder, "package.json")); - if (excluded.includes(pkgJson.name)) { - continue; - } - if (pkgJson.private === true) { - fse.moveSync(path.join(packages, folder), path.join(root, "deprecated", "packages", folder)); + const deprecatedPackages = path.join(root, "deprecated", "packages"); + for (const folder of fs.readdirSync(deprecatedPackages)) { + const pkgJson = require(path.join(deprecatedPackages, folder, "package.json")); + + if (excluded.includes(pkgJson.name)) { + continue; + } + + if (pkgJson.private !== true) { + throw new Error("package in deprecated folder is not marked private:", folder); + } else { + } } } -const deprecatedPackages = path.join(root, "deprecated", "packages"); -for (const folder of fs.readdirSync(deprecatedPackages)) { - const pkgJson = require(path.join(deprecatedPackages, folder, "package.json")); +/** + * Analyze package dependency graph. + */ +{ + const packagesData = fs.readdirSync(packages).map((pkg) => require(path.join(packages, pkg, "package.json"))); + const libsData = fs.readdirSync(libs).map((pkg) => require(path.join(libs, pkg, "package.json"))); + const clientsData = fs.readdirSync(clients).map((pkg) => require(path.join(clients, pkg, "package.json"))); - if (excluded.includes(pkgJson.name)) { - continue; - } + const allPackages = [...packagesData, ...libsData, ...clientsData]; - if (pkgJson.private !== true) { - throw new Error("package in deprecated folder is not marked private:", folder); - } else { - console.log(`"${pkgJson.name}"`); - } + const graph = new (class PackageGraph { + /** + * @param graph - map of pkg name to pkg.json objects. + */ + constructor(graph) { + this.graph = graph; + for (const md of Object.values(graph)) { + md.dependents = md.dependents ?? {}; + for (const dependency of Object.keys({ ...md.dependencies, ...md.devDependencies })) { + if (!graph[dependency]) { + // is external. + continue; + } + graph[dependency].dependents = graph[dependency].dependents ?? {}; + graph[dependency].dependents[md.name] = 1; + } + } + } + + entryPoints() { + const { graph } = this; + return Object.values(graph) + .filter((p) => { + if (p.name.startsWith("@aws-sdk/client-")) { + return false; + } + // return Object.keys(p.dependents).length === 0; + return true; + }) + .sort((a, b) => { + return Object.keys(a.dependents).length - Object.keys(b.dependents).length; + }) + .map((p) => { + const deps = Object.keys(p.dependents); + switch (p.name) { + case "@aws-sdk/karma-credential-loader": + return p.name + ": -- devtool --"; + } + if (deps.length === 0) { + return p.name + ": ---- NONE ----"; + } + if (deps.length > 100) { + return p.name + `: ** ${deps.length} packages (clients) **`; + } + if (deps.length > 5) { + return p.name + `: ** ${deps.length} packages **`; + } + return p.name + ": \n\t" + deps.join("\n\t"); + }); + } + })( + allPackages.reduce((gr, pkg) => { + gr[pkg.name] = pkg; + return gr; + }, {}) + ); + + console.log(graph.entryPoints().join("\n")); }