// SPDX-FileCopyrightText: 2026 Alexander Bates // // SPDX-License-Identifier: 0BSD // The npm packages the app ships: app/package.json's dependencies, and // theirs in turn, as installed in node_modules. Development dependencies, // such as the build tools, aren't shipped. import { existsSync, readFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; export const appDir = join(dirname(fileURLToPath(import.meta.url)), ".."); /** The directory of the package `name`, as Node would find it from `fromDir`. */ function findPackage(name, fromDir) { for (let dir = fromDir; ; dir = dirname(dir)) { const candidate = join(dir, "node_modules", name); if (existsSync(join(candidate, "package.json"))) { return candidate; } if (dirname(dir) === dir) { return undefined; } } } /** The packages the app ships, as their package.json, by directory. */ export function shippedPackages() { const packages = new Map(); const pending = [appDir]; while (pending.length > 0) { const dir = pending.pop(); const manifest = JSON.parse( readFileSync(join(dir, "package.json"), "utf8"), ); const dependencies = { ...manifest.dependencies, ...manifest.optionalDependencies, }; for (const name of Object.keys(dependencies)) { const found = findPackage(name, dir); // An optional dependency for another platform isn't installed. if (found && !packages.has(found)) { packages.set(found, undefined); pending.push(found); } } if (dir !== appDir) { packages.set(dir, manifest); } } return packages; } /** A package's license as an SPDX expression, from its package.json. */ export function licenseOf(manifest) { const { license, licenses } = manifest; if (typeof license === "string") { return license; } if (license?.type) { return license.type; } // An old form: a list of licenses, any of which applies. if (Array.isArray(licenses)) { return licenses .map((l) => (typeof l === "string" ? l : l.type)) .join(" OR "); } return undefined; }