Skip to content

Instantly share code, notes, and snippets.

@Atulin
Created May 21, 2025 00:33
Show Gist options
  • Select an option

  • Save Atulin/ab93cd1e30509f1ac9458d9205b8fcef to your computer and use it in GitHub Desktop.

Select an option

Save Atulin/ab93cd1e30509f1ac9458d9205b8fcef to your computer and use it in GitHub Desktop.
Get .NET project nuggie data
import { dirname, join } from "node:path";
import { Glob } from "bun";
import { ReturningHtmlRewriter } from "./helpers/ReturningHtmlRewriter";
const ROOT = dirname(Bun.main);
const OUTFILE = join(ROOT, "..", "..", "wwwroot", "LICENSES.txt");
const PROJECT_ROOT = join(ROOT, "..", "..", "..");
interface Source {
name: string;
type: "npm" | "nuget";
path: string;
}
const sources: Source[] = [
{ name: "Javascript", type: "npm", path: join(ROOT, "..", "package.json*") },
{
name: ".NET",
type: "nuget",
path: join(PROJECT_ROOT, "*", "*.csproj"),
},
];
const csprojRewriter = new ReturningHtmlRewriter<{ name: string; version: string }>().on("PackageReference", {
element(el, ctx) {
const name = el.getAttribute("Include");
const version = el.getAttribute("Version");
if (name && version) {
ctx.add({ name, version });
}
},
});
const allPackages: { name: string; version: string; license: string; licenseUrl: string }[] = [];
const maxLengths: Record<keyof (typeof allPackages)[number], number> = {
name: 0,
version: 0,
license: 0,
licenseUrl: 0,
};
for (const { name, type, path } of sources) {
for await (const file of new Glob(path).scan()) {
console.log(`Processing ${file}`);
const contents = await Bun.file(file).text();
if (type === "nuget") {
const packages = csprojRewriter.parse(contents);
for (const { name, version } of packages) {
console.log(`\t${name} @${version}`);
const n = name.toLowerCase();
const v = version.toLowerCase();
const deetsRes = await fetch(`https://api.nuget.org/v3/registration5-semver1/${n}/${v}.json`);
if (!deetsRes.ok) {
console.error(`Failed to fetch details for ${name} ${version}: ${deetsRes.statusText}`);
continue;
}
const deets = await deetsRes.json();
const entryRes = await fetch(deets.catalogEntry);
if (!entryRes.ok) {
console.error(`Failed to fetch license for ${name} ${version}: ${entryRes.statusText}`);
continue;
}
const entry = await entryRes.json();
const pkg = {
name,
version,
license: entry.licenseExpression ?? "",
licenseUrl: entry.licenseUrl ?? "",
};
allPackages.push(pkg);
maxLengths.name = Math.max(maxLengths.name, pkg.name.length);
maxLengths.version = Math.max(maxLengths.version, pkg.version.length);
maxLengths.license = Math.max(maxLengths.license, pkg.license.length);
maxLengths.licenseUrl = Math.max(maxLengths.licenseUrl, pkg.licenseUrl.length);
}
}
}
}
const lines: string[] = [];
for (const pkg of allPackages) {
lines.push(
`${pkg.name.padEnd(maxLengths.name)} | ${pkg.version.padEnd(maxLengths.version)} | ${pkg.license.padEnd(maxLengths.license)} | ${pkg.licenseUrl.padEnd(
maxLengths.licenseUrl,
)}`,
);
}
console.log(lines.join("\n"));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment