@augment-vir/node
Version:
A collection of augments, helpers types, functions, and classes only for Node.js (backend) JavaScript environments.
76 lines (66 loc) • 2.74 kB
text/typescript
import {check} from '@augment-vir/assert';
import {filterMap, fromAsyncIterable} from '@augment-vir/common';
import {existsSync} from 'node:fs';
import {glob, readFile} from 'node:fs/promises';
import {join} from 'node:path';
import {type PackageJson} from 'type-fest';
import {findAncestor, joinFilesToDir} from '../path/ancestor.js';
/**
* Finds all `package.json` files contained within the workspaces present in the current
* `startDirPath`. A workspace root dir is found by recursively looking for a parent
* `package-lock.json` file.
*
* @category Node : Npm
* @category Package : @augment-vir/node
* @throws If no directory with a `package-lock.json` file is found.
* @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
*/
export async function findAllPackageJsonFilePaths(startDirPath: string) {
const packageRootDir = findAncestor(startDirPath, (dir) =>
existsSync(join(dir, 'package-lock.json')),
);
if (!packageRootDir) {
throw new Error(
`Cannot find all package.json files: failed to find any directory with a package-lock.json file. Started at '${startDirPath}'.`,
);
}
const rootPackageJsonPath = join(packageRootDir, 'package.json');
return [
rootPackageJsonPath,
...(await getWorkspacePackageJsonFilePaths(packageRootDir)),
];
}
/**
* Get all workspace package.json paths starting at the given directory path. The output is string
* sorted to keep it stable.
*
* @category Node : Npm
* @category Package : @augment-vir/node
* @throws Error if there is no `package.json` file at the given `rootDirPath`.
* @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
*/
export async function getWorkspacePackageJsonFilePaths(rootDirPath: string): Promise<string[]> {
const packageJson: PackageJson = JSON.parse(
await readFile(join(rootDirPath, 'package.json'), 'utf8'),
);
/* node:coverage ignore next 3: this package only uses one type of workspace */
const patterns = check.isArray(packageJson.workspaces)
? packageJson.workspaces
: packageJson.workspaces?.packages || [];
const matchedPaths: string[] = joinFilesToDir(
rootDirPath,
(
await Promise.all(
patterns.map(async (pattern) => {
return await fromAsyncIterable(glob(pattern, {cwd: rootDirPath}));
}),
)
).flat(),
);
const workspacePackageJsonPaths = filterMap(
matchedPaths,
(matchedPath) => join(matchedPath, 'package.json'),
(packageJsonPath) => existsSync(packageJsonPath),
);
return workspacePackageJsonPaths.sort();
}