import { assert, type Equals } from "tsafe/assert"; import { is } from "tsafe/is"; import type { BuildContext } from "../shared/buildContext"; import type { UiModuleMeta } from "./uiModuleMeta"; import { z } from "zod"; import { id } from "tsafe/id"; import * as fsPr from "fs/promises"; import { SemVer } from "../tools/SemVer"; import { same } from "evt/tools/inDepth/same"; import { runPrettier, getIsPrettierAvailable } from "../tools/runPrettier"; import { npmInstall } from "../tools/npmInstall"; export type BuildContextLike = { packageJsonFilePath: string; }; assert(); export type UiModuleMetaLike = { moduleName: string; peerDependencies: Record; }; assert(); export async function installUiModulesPeerDependencies(params: { buildContext: BuildContextLike; uiModuleMetas: UiModuleMetaLike[]; }): Promise { const { buildContext, uiModuleMetas } = params; const { uiModulesPerDependencies } = (() => { const uiModulesPerDependencies: Record = {}; for (const { peerDependencies } of uiModuleMetas) { for (const [peerDependencyName, versionRange_candidate] of Object.entries( peerDependencies )) { const versionRange = (() => { const versionRange_current = uiModulesPerDependencies[peerDependencyName]; if (versionRange_current === undefined) { return versionRange_candidate; } if (versionRange_current === "*") { return versionRange_candidate; } if (versionRange_candidate === "*") { return versionRange_current; } const { versionRange } = [ versionRange_current, versionRange_candidate ] .map(versionRange => ({ versionRange, semVer: SemVer.parse( (() => { if ( versionRange.startsWith("^") || versionRange.startsWith("~") ) { return versionRange.slice(1); } return versionRange; })() ) })) .sort((a, b) => SemVer.compare(b.semVer, a.semVer))[0]; return versionRange; })(); uiModulesPerDependencies[peerDependencyName] = versionRange; } } return { uiModulesPerDependencies }; })(); const parsedPackageJson = await (async () => { type ParsedPackageJson = { dependencies?: Record; devDependencies?: Record; }; const zParsedPackageJson = (() => { type TargetType = ParsedPackageJson; const zParsedPackageJson = z.object({ dependencies: z.record(z.string()).optional(), devDependencies: z.record(z.string()).optional() }); type InferredType = z.infer; assert>(); return id>(zParsedPackageJson); })(); const parsedPackageJson = JSON.parse( (await fsPr.readFile(buildContext.packageJsonFilePath)).toString("utf8") ); zParsedPackageJson.parse(parsedPackageJson); assert(is(parsedPackageJson)); return parsedPackageJson; })(); const parsedPackageJson_before = JSON.parse(JSON.stringify(parsedPackageJson)); for (const [moduleName, versionRange] of Object.entries(uiModulesPerDependencies)) { if (moduleName.startsWith("@types/")) { (parsedPackageJson.devDependencies ??= {})[moduleName] = versionRange; continue; } if (parsedPackageJson.devDependencies !== undefined) { delete parsedPackageJson.devDependencies[moduleName]; } (parsedPackageJson.dependencies ??= {})[moduleName] = versionRange; } if (same(parsedPackageJson, parsedPackageJson_before)) { return; } let packageJsonContentStr = JSON.stringify(parsedPackageJson, null, 2); format: { if (!(await getIsPrettierAvailable())) { break format; } packageJsonContentStr = await runPrettier({ sourceCode: packageJsonContentStr, filePath: buildContext.packageJsonFilePath }); } await fsPr.writeFile(buildContext.packageJsonFilePath, packageJsonContentStr); npmInstall({ packageJsonDirPath: buildContext.packageJsonFilePath }); process.exit(0); }