import { assert, type Equals } from "tsafe/assert"; import { id } from "tsafe/id"; import { z } from "zod"; import { join as pathJoin } from "path"; import * as fsPr from "fs/promises"; import { is } from "tsafe/is"; import { getInstalledModuleDirPath } from "../tools/getInstalledModuleDirPath"; export async function listInstalledModules(params: { packageJsonFilePath: string; projectDirPath: string; filter: (params: { moduleName: string }) => boolean; }): Promise<{ moduleName: string; version: string; dirPath: string }[]> { const { packageJsonFilePath, projectDirPath, filter } = params; const parsedPackageJson = await readPackageJsonDependencies({ packageJsonFilePath }); const uiModuleNames = ( [parsedPackageJson.dependencies, parsedPackageJson.devDependencies] as const ) .filter(obj => obj !== undefined) .map(obj => Object.keys(obj)) .flat() .filter(moduleName => filter({ moduleName })); const result = await Promise.all( uiModuleNames.map(async moduleName => { const dirPath = await getInstalledModuleDirPath({ moduleName, packageJsonFilePath, projectDirPath }); const { version } = await readPackageJsonVersion({ packageJsonFilePath: pathJoin(dirPath, "package.json") }); return { moduleName, version, dirPath } as const; }) ); return result; } const { readPackageJsonDependencies } = (() => { type ParsedPackageJson = { dependencies?: Record; devDependencies?: Record; }; const zParsedPackageJson = (() => { type TargetType = ParsedPackageJson; const zTargetType = z.object({ dependencies: z.record(z.string()).optional(), devDependencies: z.record(z.string()).optional() }); assert, TargetType>>(); return id>(zTargetType); })(); async function readPackageJsonDependencies(params: { packageJsonFilePath: string }) { const { packageJsonFilePath } = params; const parsedPackageJson = JSON.parse( (await fsPr.readFile(packageJsonFilePath)).toString("utf8") ); zParsedPackageJson.parse(parsedPackageJson); assert(is(parsedPackageJson)); return parsedPackageJson; } return { readPackageJsonDependencies }; })(); const { readPackageJsonVersion } = (() => { type ParsedPackageJson = { version: string; }; const zParsedPackageJson = (() => { type TargetType = ParsedPackageJson; const zTargetType = z.object({ version: z.string() }); assert, TargetType>>(); return id>(zTargetType); })(); async function readPackageJsonVersion(params: { packageJsonFilePath: string }) { const { packageJsonFilePath } = params; const parsedPackageJson = JSON.parse( (await fsPr.readFile(packageJsonFilePath)).toString("utf8") ); zParsedPackageJson.parse(parsedPackageJson); assert(is(parsedPackageJson)); return parsedPackageJson; } return { readPackageJsonVersion }; })();