// // Copyright 2021 DXOS.org // import chalk from 'chalk'; import { existsSync, readFileSync, writeFileSync } from 'fs'; import path from 'path'; import sortPackageJson from 'sort-package-json'; import { Argv, CommandModule } from 'yargs'; import { checkStaleDeps, checkInstalled, getProjects, sort, spawn } from '../helpers'; /** * NPM Dependencies. */ export const depsModule: CommandModule = { command: 'deps', describe: 'NPM dependencies.', handler: (argv: any) => {}, builder: (yargs: Argv) => yargs .demandCommand() .command({ command: 'check', describe: 'Run npm-check-updates.', builder: (yargs: Argv) => yargs, handler: async ({ verbose }: any) => { try { await spawn('ncu --packageFile ./package.json').run({ log: true, verbose: true }); } catch (err) { checkInstalled(err, 'ncu'); } } }) .command({ command: 'stale', describe: 'Check for stale deps.', builder: (yargs: Argv) => yargs .option('whitelist', { type: 'boolean', default: false }), handler: async ({ whitelist }: { whitelist?: boolean }) => { await checkStaleDeps('./package.json', { whitelist }); } }) // TODO(burdon): Move to build tool. .command({ command: 'sort', describe: 'Sort JSON files.', builder: (yargs: Argv) => yargs .option('files', { default: 'package.json,tsconfig.json' }), handler: async ({ files, verbose }: any) => { const filenames: string[] = files.split(','); // Custom options. // CI updates tsconfig.json to update dependencies. const sorterMap: { [filename: string]: (json: string) => string } = { 'package.json': json => sortPackageJson(json), // https://www.typescriptlang.org/tsconfig // https://www.npmjs.com/package/@monorepo-utils/workspaces-to-typescript-project-references 'tsconfig.json': json => JSON.stringify(sort(JSON.parse(json), { map: { '.': ['extends'], '.references': (value: any) => value.path } }), null, 2) + '\n' } const runSort = (directory: string, filename: string) => { const filepath = path.join(directory, filename); try { // TODO(burdon): Doesn't support comments. // TODO(burdon): Doesn't sort subkeys for non package.json files. // TODO(burdon): Custom sorting (e.g., tsconfig references by path). const sorter = sorterMap[filename]; if (sorter) { const json = readFileSync(filepath, 'utf-8'); const sorted = sorter(json); writeFileSync(filepath, sorted, 'utf-8'); return true; } } catch (err) { console.log((err as Error).message); return false; } } let projects = [{ fullPath: process.cwd() }]; // Default for non-rush projects. try { projects = await getProjects() as any; } catch { // Ignore. } for (const { fullPath } of projects) { filenames.forEach(filename => { if (existsSync(filename)) { const ok = runSort(fullPath, filename); if (verbose || !ok) { console.log((ok ? chalk.green : chalk.red)(`${path.join(fullPath, filename)}`)); } } }); } } }) };