packages/brookjs-cli/src/commands/FormatCommand/index.tsx
import React, { useEffect } from 'react';import { Argv } from 'yargs';import { useDelta, RootJunction } from 'brookjs-silt';import { EddyReducer, loop } from 'brookjs-eddy';import { ActionType, getType, createAsyncAction, createAction,} from 'typesafe-actions';import Kefir from 'kefir';import { Delta, Maybe, unreachable } from 'brookjs-types';import * as t from 'io-ts';import { ofType, sampleByAction } from 'brookjs-flow';import { Box, Color } from 'ink';import { Command, useExit, ExitError } from '../../cli';import * as glob from '../../glob';import { service as fs } from '../../fs';import { ESLintService } from '../../eslint';import * as prettier from '../../prettier'; type Args = {}; type State = { status: 'init' | 'globbing' | 'formatting' | 'finished' | 'errored'; cwd: string; rc: Maybe<RC>; paths: string[]; results: Record<string, FormatResults>; error: Maybe<Error>;}; type Action = ActionType<typeof glob.actions | typeof actions>; type RC = t.TypeOf<typeof RC>; const RC = t.partial({ dir: t.string,}); type FormatResults = { path: string; contents: string; changed: boolean;}; const actions = { fileFormatted: createAction('FILE_FORMATTED')<FormatResults>(), format: createAsyncAction( 'FORMAT_REQUESTED', 'FORMAT_SUCCEEDED', 'FORMAT_FAILED', )<void, void, Error>(),}; const reducer: EddyReducer<State, Action> = ( state = initialState({}, { rc: null, cwd: '/' }), action,) => { switch (action.type) { case getType(glob.actions.format.request): return { ...state, status: 'globbing', }; case getType(glob.actions.format.success): return loop( { ...state, status: 'formatting', paths: action.payload }, actions.format.request(), ); case getType(actions.fileFormatted): return { ...state, results: { ...state.results, [action.payload.path]: action.payload, }, }; case getType(actions.format.success): return { ...state, status: 'finished', }; case getType(actions.format.failure): return { ...state, status: 'errored', error: action.payload, }; default: return state; }}; const initialState = ( args: Args, { rc, cwd }: { rc: unknown; cwd: string },): State => ({ status: 'init', cwd, rc: RC.decode(rc).fold( () => null, rc => rc, ), paths: [], results: {}, error: null,}); Function `exec` has 36 lines of code (exceeds 25 allowed). Consider refactoring.const exec: Delta<Action, State> = (action$, state$) => { const glob$ = glob.delta( action$.thru(ofType(glob.actions.format.request)), state$.map(state => ({ cwd: state.cwd, rc: state.rc, })), ); const format$ = state$ .thru(sampleByAction(action$, actions.format.request)) .flatMap(state => { const eslint = ESLintService.create({ cwd: state.cwd, fix: true }); return Kefir.constant(state.paths) .flatten(paths => paths) .flatMapConcurLimit( file => fs.readFile(file).map(buffer => ({ buffer, file })), 4, ) .flatMap(({ buffer, file }) => prettier.format(file, buffer)) .flatMap(result => eslint.check(result.path, result.contents).map(r => ({ path: result.path, contents: r.results[0].output ?? result.contents, changed: result.changed || r.results[0].output != null, })), ) .flatMap(result => result.changed ? fs.writeFile(result.path, result.contents).map(() => result) : Kefir.constant(result), ) .map(actions.fileFormatted) .concat(Kefir.constant(actions.format.success())) .takeErrors(1) .flatMapErrors(err => Kefir.constant(actions.format.failure(err))); }); return Kefir.merge<Action, never>([glob$, format$]);}; const Errored: React.FC<{ message: string }> = ({ message }) => { useExit(new ExitError(1)); return ( <Box flexDirection="column"> <Color red>Failure! Error formatting files.</Color> <Color redBright>{message}</Color> </Box> );}; Function `View` has a Cognitive Complexity of 7 (exceeds 5 allowed). Consider refactoring.const View: React.FC<State> = ({ status, paths, results, error }) => { switch (status) { case 'init': case 'globbing': case 'formatting': return ( <Box> <Color yellow>Formatting...</Color> </Box> ); case 'finished': const total = paths.reduce( (total, path) => total + (results[path].changed ? 1 : 0), 0, );Similar blocks of code found in 2 locations. Consider refactoring. return ( <Box flexDirection="column"> <Color green>Success! All files have been formatted.</Color> <Color greenBright> Formatted {total} file{total === 1 ? '' : 's'} </Color> </Box> ); case 'errored': return <Errored message={error?.message ?? 'Unknown error.'} />; default: return unreachable(status); }}; const FormatCommand: Command<Args> = { cmd: 'format', describe: 'Format all the files in the brookjs application.', builder(yargs: Argv<Args>): Argv<Args> { return yargs; }, View: ({ args, rc, cwd }) => { const { state, root$, dispatch } = useDelta( reducer, initialState(args, { rc, cwd }), exec, ); useEffect(() => { dispatch(glob.actions.format.request()); }, [dispatch]); return ( <RootJunction root$={root$}> <View {...state} /> </RootJunction> ); },}; export default FormatCommand;