import { cp, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const destination = path.join(root, "public"); for (const name of [ "LICENSE", "README.md", "CHANGELOG.md", "CONTRIBUTING.md", "SECURITY.md", "SOURCE.md", "THIRD_PARTY_NOTICES.md", ]) { await readFile(path.join(root, name)); await cp(path.join(root, name), path.join(destination, name)); } for (const directory of ["LICENSES", "docs"]) { const output = path.join(destination, directory); await rm(output, { recursive: true, force: true }); await cp(path.join(root, directory), output, { recursive: true }); } const lock = JSON.parse( await readFile(path.join(root, "package-lock.json"), "utf8"), ); const sections = []; for (const [location, locked] of Object.entries(lock.packages ?? {}).sort( ([a], [b]) => a.localeCompare(b), )) { if (!location.includes("node_modules/") || locked.dev === true) continue; const packageDirectory = path.join(root, location); const details = JSON.parse( await readFile(path.join(packageDirectory, "package.json"), "utf8"), ); const candidates = (await readdir(packageDirectory)) .filter((name) => /^(?:licen[cs]e|copying|notice)(?:\.|$)/iu.test(name)) .sort(); const texts = []; for (const candidate of candidates) { try { texts.push( "--- " + candidate + " ---\n" + (await readFile(path.join(packageDirectory, candidate), "utf8")), ); } catch { /* directory */ } } sections.push( "=".repeat(78) + "\n" + details.name + "@" + details.version + "\nDeclared licence: " + (details.license ?? locked.license ?? "See upstream") + "\n" + "=".repeat(78) + "\n" + (texts.join("\n\n") || "See upstream package metadata."), ); } await mkdir(path.join(destination, "LICENSES"), { recursive: true }); await writeFile( path.join(destination, "LICENSES/npm-runtime-licenses.txt"), sections.join("\n\n").trimEnd() + "\n", ); console.log("Prepared release documentation");