waka-pm
Version:
a pnpm supplement for enforcing consistent versions across all workspaces
321 lines • 13.9 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseWorkspaceDir = exports.mapNPMPackageDetails = exports.getDetailKey = exports.getNPMPackageDetails = exports.getWakaPackageDocuments = exports.getWakaPackages = exports.getWakaPackageDocument = exports.getWakaPackage = exports.getRawWakaPackageYamlData = exports.getWakaRootDocument = exports.getWakaRoot = exports.getRootNPMPackageFile = exports.getNPMPackageJsonContents = exports.getNPMPackageFiles = exports.getWakaPackageFiles = exports.getWakaRootFile = exports.getNPMPackageFile = exports.getWakaPackageFile = exports.getAllPackageDirectories = exports.getNPMPackageDir = exports.getWorkspaceDirectoryByPackage = exports.getWorkspaceDirectories = exports.getNPMPackageName = void 0;
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const glob_1 = require("glob");
const yaml_1 = __importDefault(require("yaml"));
const schema_1 = require("../schema");
const file_1 = require("../file");
const packageDirToNameCache = new Map();
const packageNameToDirCache = new Map();
let workspaceDirCache;
function toDirectoryOnly(p) {
if (fs_1.default.existsSync(p) === false) {
throw new Error(`Path ${p} does not exist.`);
}
if (fs_1.default.lstatSync(p).isDirectory()) {
return p;
}
return path_1.default.dirname(p);
}
function getNPMPackageName(packageJsonFile) {
const fullPath = path_1.default.resolve(packageJsonFile);
const dir = toDirectoryOnly(fullPath);
if (packageDirToNameCache.has(dir)) {
return packageDirToNameCache.get(dir);
}
const rawData = fs_1.default.readFileSync(fullPath, 'utf8');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const pkgJsonData = JSON.parse(rawData);
const pkgName = pkgJsonData.name;
packageDirToNameCache.set(dir, pkgName);
packageNameToDirCache.set(pkgName, dir);
return pkgName;
}
exports.getNPMPackageName = getNPMPackageName;
async function getWorkspaceDirectories(repoRootDir) {
if (workspaceDirCache && Object.keys(workspaceDirCache).length > 0) {
return workspaceDirCache;
}
const pnpmWorkspaceYaml = path_1.default.join(repoRootDir, 'pnpm-workspace.yaml');
const rootPackageJson = path_1.default.join(repoRootDir, 'package.json');
let workspaceDirs = [];
if (fs_1.default.existsSync(pnpmWorkspaceYaml)) {
const rawData = fs_1.default.readFileSync(pnpmWorkspaceYaml, 'utf8');
workspaceDirs = yaml_1.default.parse(rawData).packages;
}
else if (fs_1.default.existsSync(rootPackageJson)) {
const rawData = fs_1.default.readFileSync(rootPackageJson, 'utf8');
workspaceDirs = JSON.parse(rawData)
.workspaces.packages;
}
else {
throw new Error('No pnpm-workspace.yaml or root package.json found');
}
const workspacePackageJsons = workspaceDirs.map((dir) => `${dir}/package.json`);
const foundJsons = (await (0, glob_1.glob)(workspacePackageJsons, {
ignore: ['**/node_modules/**'],
cwd: repoRootDir,
})).map((p) => path_1.default.join(repoRootDir, p));
const foundDirs = foundJsons
.map((json) => {
const dir = path_1.default.relative(repoRootDir, path_1.default.dirname(json));
const pkgName = getNPMPackageName(json);
return { [pkgName]: dir };
})
.reduce((acc, p) => {
return { ...acc, ...p };
});
workspaceDirCache = foundDirs;
const rootName = getNPMPackageName(rootPackageJson);
workspaceDirCache[rootName] = '';
return foundDirs;
}
exports.getWorkspaceDirectories = getWorkspaceDirectories;
async function getWorkspaceDirectoryByPackage(repoRootDir, packageName) {
const workspaces = await getWorkspaceDirectories(repoRootDir);
const workspace = workspaces[packageName];
if (!workspace) {
throw new Error(`Package ${packageName} does not exist.`);
}
return workspace;
}
exports.getWorkspaceDirectoryByPackage = getWorkspaceDirectoryByPackage;
async function getNPMPackageDir(packageName, repoRootDir) {
if (packageNameToDirCache.has(packageName)) {
return packageNameToDirCache.get(packageName);
}
const packageDirRelative = await getWorkspaceDirectoryByPackage(repoRootDir, packageName);
const dir = toDirectoryOnly(path_1.default.join(repoRootDir, packageDirRelative));
const packageDir = path_1.default.resolve(dir);
packageNameToDirCache.set(packageName, packageDir);
packageDirToNameCache.set(packageDir, packageName);
return packageDir;
}
exports.getNPMPackageDir = getNPMPackageDir;
async function getAllPackageDirectories(repoRootDir, opts) {
const packageDirs = Object.values(await getWorkspaceDirectories(repoRootDir));
if (opts?.includeRoot === false) {
return packageDirs.filter((p) => p !== '' && p !== '.' && p !== './');
}
return packageDirs;
}
exports.getAllPackageDirectories = getAllPackageDirectories;
async function getPackageFile(filename, packageDir, opts) {
const f = path_1.default.join(packageDir, filename);
if (opts?.ensureExists && !fs_1.default.existsSync(f)) {
throw new Error(`File ${f} does not exist.`);
}
return Promise.resolve(f);
}
async function getWakaPackageFile(packageDir, opts) {
packageDir = toDirectoryOnly(packageDir);
return getPackageFile('waka-package.yaml', packageDir, opts);
}
exports.getWakaPackageFile = getWakaPackageFile;
async function getNPMPackageFile(packageDir, opts) {
packageDir = toDirectoryOnly(packageDir);
return getPackageFile('package.json', packageDir, opts);
}
exports.getNPMPackageFile = getNPMPackageFile;
function getWakaRootFile(repoRootDir, opts) {
const rootFile = path_1.default.join(repoRootDir, 'waka-root.yaml');
if (opts?.ensureExists && !fs_1.default.existsSync(rootFile)) {
throw new Error(`File ${rootFile} does not exist.`);
}
return Promise.resolve(rootFile);
}
exports.getWakaRootFile = getWakaRootFile;
async function getWakaPackageFiles(repoRootDir, opts) {
const packageDirs = await getAllPackageDirectories(repoRootDir, {
includeRoot: false,
});
const pkgFilePromises = packageDirs.map(async (p) => {
const f = await getWakaPackageFile(path_1.default.join(repoRootDir, p), opts);
return f;
});
const allPackageFiles = await Promise.all(pkgFilePromises);
if (opts?.includeRoot) {
const rootFile = await getWakaRootFile(repoRootDir, {
ensureExists: opts?.ensureExists,
});
allPackageFiles.push(rootFile);
}
return allPackageFiles.filter((f) => !!f);
}
exports.getWakaPackageFiles = getWakaPackageFiles;
async function getNPMPackageFiles(repoRootDir, opts) {
const packageDirs = await getAllPackageDirectories(repoRootDir, {
includeRoot: opts?.includeRoot ?? false,
});
const pkgFilePromises = packageDirs.map(async (p) => {
const f = await getNPMPackageFile(path_1.default.join(repoRootDir, p), opts);
return f;
});
return (await Promise.all(pkgFilePromises)).filter((f) => !!f);
}
exports.getNPMPackageFiles = getNPMPackageFiles;
async function getNPMPackageJsonContents(packageDir) {
packageDir = toDirectoryOnly(packageDir);
const fullPath = await getNPMPackageFile(packageDir, { ensureExists: true });
const rawData = fs_1.default.readFileSync(fullPath, 'utf8');
const pkgJsonData = JSON.parse(rawData);
return pkgJsonData;
}
exports.getNPMPackageJsonContents = getNPMPackageJsonContents;
function getRootNPMPackageFile(repoRootDir, opts) {
const rootFile = path_1.default.join(repoRootDir, 'package.json');
if (opts?.ensureExists && !fs_1.default.existsSync(rootFile)) {
throw new Error(`File ${rootFile} does not exist.`);
}
return Promise.resolve(rootFile);
}
exports.getRootNPMPackageFile = getRootNPMPackageFile;
async function getRawWakaRootYamlData(repoRootDir) {
const rootFile = await getWakaRootFile(repoRootDir, { ensureExists: true });
const rawData = fs_1.default.readFileSync(rootFile, 'utf8');
return rawData;
}
async function getWakaRoot(repoRootDir) {
const rawData = await getRawWakaRootYamlData(repoRootDir);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const root = yaml_1.default.parse(rawData);
const rootParsed = schema_1.rootSchema.parse(root);
return rootParsed;
}
exports.getWakaRoot = getWakaRoot;
async function getWakaRootDocument(repoRootDir) {
const rawData = await getRawWakaRootYamlData(repoRootDir);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const root = yaml_1.default.parse(rawData);
// still parse for validation purposes
schema_1.rootSchema.parse(root);
const doc = yaml_1.default.parseDocument(rawData);
const rootParsed = schema_1.RootDocument.instanceFromDocument(doc);
return rootParsed;
}
exports.getWakaRootDocument = getWakaRootDocument;
async function getRawWakaPackageYamlData(packageDirectory) {
const packageDir = toDirectoryOnly(packageDirectory);
const wakaPackageFile = await getWakaPackageFile(packageDir, {
ensureExists: true,
});
const rawData = fs_1.default.readFileSync(wakaPackageFile, 'utf8');
return rawData;
}
exports.getRawWakaPackageYamlData = getRawWakaPackageYamlData;
async function getWakaPackage(packageDirectory) {
const rawData = await getRawWakaPackageYamlData(packageDirectory);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const pkg = yaml_1.default.parse(rawData);
const pkgParsed = schema_1.packageSchema.parse(pkg);
return pkgParsed;
}
exports.getWakaPackage = getWakaPackage;
async function getWakaPackageDocument(packageDirectory) {
const rawData = await getRawWakaPackageYamlData(packageDirectory);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const pkg = yaml_1.default.parse(rawData);
// still parse for validation purposes
schema_1.packageSchema.parse(pkg);
const doc = yaml_1.default.parseDocument(rawData);
return schema_1.PackageDocument.instanceFromDocument(doc);
}
exports.getWakaPackageDocument = getWakaPackageDocument;
async function getWakaPackagesInFormat(repoRootDir, format) {
const packageFiles = await getWakaPackageFiles(repoRootDir, {
ensureExists: true,
});
return (await Promise.all(packageFiles.map(async (p) => {
const packageDir = path_1.default.dirname(p);
const packageJsonFile = await getNPMPackageFile(packageDir, {
ensureExists: true,
});
const packageName = getNPMPackageName(packageJsonFile);
const pkgParsed = await format(p);
return { [packageName]: pkgParsed };
}))).reduce((acc, p) => {
return { ...acc, ...p };
}, {});
}
async function getWakaPackages(repoRootDir) {
return getWakaPackagesInFormat(repoRootDir, getWakaPackage);
}
exports.getWakaPackages = getWakaPackages;
async function getWakaPackageDocuments(repoRootDir) {
return getWakaPackagesInFormat(repoRootDir, getWakaPackageDocument);
}
exports.getWakaPackageDocuments = getWakaPackageDocuments;
async function getNPMPackageDetails(repoRootDir, opts) {
let pkgJsons = await getNPMPackageFiles(repoRootDir, {
ensureExists: true,
includeRoot: false,
});
if (opts?.includeRoot) {
const rootPkgJson = await getRootNPMPackageFile(repoRootDir, {
ensureExists: true,
});
pkgJsons = [...pkgJsons, rootPkgJson];
}
const details = [];
for (const p of pkgJsons) {
const pkgJsonData = await getNPMPackageJsonContents(p);
schema_1.npmDepTypes.forEach((depType) => {
const deps = pkgJsonData[depType];
if (deps) {
Object.keys(deps).forEach((depName) => {
details.push({
name: depName,
version: deps[depName],
type: depType,
packagePath: p,
packageName: getNPMPackageName(p),
});
});
}
});
}
return details;
}
exports.getNPMPackageDetails = getNPMPackageDetails;
function getDetailKey(detail, mapBy = ['name']) {
return mapBy.map((mapByKey) => detail[mapByKey]).join('|');
}
exports.getDetailKey = getDetailKey;
function mapNPMPackageDetails(details, mapBy = ['name']) {
const m = details.reduce((acc, pkgDetail) => {
const fullKey = getDetailKey(pkgDetail, mapBy);
if (!acc[fullKey]) {
acc[fullKey] = [];
}
acc[fullKey].push(pkgDetail);
return acc;
}, {});
return m;
}
exports.mapNPMPackageDetails = mapNPMPackageDetails;
async function parseWorkspaceDir(repoRootDir, currentDir, packageNameOrRelativePath) {
const isSub = (0, file_1.isSubDirOfMonoRepo)(currentDir);
const isRoot = (0, file_1.isMonoRepoRoot)(currentDir);
if ((packageNameOrRelativePath ?? '') === '') {
if (isSub && !isRoot) {
return currentDir;
}
return repoRootDir;
}
const fullPath = path_1.default.resolve(path_1.default.join(repoRootDir, packageNameOrRelativePath));
if (fs_1.default.existsSync(fullPath)) {
return fullPath;
}
if (packageNameOrRelativePath ?? '' !== '') {
const dir = await getNPMPackageDir(packageNameOrRelativePath, repoRootDir);
return dir;
}
throw new Error(`Could not determine package directory for ${packageNameOrRelativePath} or ${currentDir}`);
}
exports.parseWorkspaceDir = parseWorkspaceDir;
//# sourceMappingURL=read.js.map