import { exec } from 'child_process'; import findNearestFile from 'find-nearest-file'; import * as fs from 'fs'; import * as path from 'path'; import { promisify } from 'util'; import { exitCode } from '../../common'; const execAsync = promisify(exec); /** * Regex to determine version of yarn installed in project: Classic, or Modern. * Required to correctly build yarn command to retrieve list of installed packages. */ const yarnClassicVersionRegex = /^1\..*$/gim; /** * Regex for Mosaic libraries. */ const mosaicLibraryRegex = /(?@axinom\/mosaic-)(?[-A-Za-z0-9]+)/gim; /** * Find all Mosaic packages used in project. * @returns list of installed packages. */ const findInstalledPackages = async (): Promise => { let installedMosaicLibs: string[] = []; const yarnVersionResult = await execAsync('yarn -v'); if (yarnVersionResult.stderr) { console.log(yarnVersionResult.stderr); } if (yarnVersionResult.stdout) { const packagesListCommand = yarnClassicVersionRegex.test( yarnVersionResult.stdout, ) ? 'yarn list --pattern @axinom/mosaic-* --depth=0' : 'yarn info @axinom/mosaic-* --recursive --all --name-only'; const packagesListResult = await execAsync(packagesListCommand); if (packagesListResult.stdout) { installedMosaicLibs = [ ...new Set(packagesListResult.stdout.match(mosaicLibraryRegex) ?? []), ]; } if (packagesListResult.stderr) { console.log(packagesListResult.stderr); } } return installedMosaicLibs; }; /** * Provides path to '.mosaic' configuration file. * Path to file provided based on the location of `yarn.lock`. */ export const getExtensionConfigPath = (): string => { const yarnLockFilePath = findNearestFile('yarn.lock'); if (yarnLockFilePath) { return path.resolve(path.dirname(yarnLockFilePath), '.mosaic'); } return path.resolve('.mosaic'); }; /** * Creates `.mosaic` configuration file with list of libraries, that provide extension for Mosaic CLI. */ export const createExtensionConfig = async (): Promise => { console.log(`Starting extension configuration generation!`); const installedMosaicLibs = await findInstalledPackages(); const extensions: string[] = []; await Promise.all( installedMosaicLibs.map(async (lib: string) => { //filter libraries, that have cli extension try { const result = await import(lib); if (result.cliExtension) { extensions.push(lib); } } catch (error) { //mosaic libraries, that are always(?) failing to load: //all `@axinom/mosaic-*-workflows`, @axinom/mosaic-portal, @axinom/mosaic-ui, @axinom/mosaic-home, @axinom/mosaic-id-link //todo: extend regex to exclude libraries? console.log(error); process.exit(exitCode); } }), ); console.log(`Modular CLI extensions: ${extensions}`); //save library names, that can be used in command line const configFilePath = getExtensionConfigPath(); const config = `CLI_EXTENSIONS=${extensions.join(',')}`; fs.writeFileSync(configFilePath, config); console.log(`Success! Extensions configuration file path: ${configFilePath}`); };