Shuunen/repo-checker

View on GitHub
src/main.ts

Summary

Maintainability
A
0 mins
Test Coverage
import arg from 'arg'
import { parseJson } from 'shuutils'
import { name } from '../package.json'
import { check } from './check'
import { dataDefaults, dataFileName, templatePath, type ProjectData } from './constants'
import { log } from './logger'
import { fileExists, join, readFileInFolder, resolve, writeFile } from './utils'

function getTarget(argument = '') {
  if (argument.length > 0) return resolve(argument)
  log.info('no target specified via : --target=path/to/directory')
  log.info('targeting current directory...')
  return process.cwd()
}

function showVersion() {
  log.info(`${name} version : __unique-mark__`)
  return { failed: [], passed: ['show-version'], warnings: [] }
}

function showHelp() {
  log.info(`usage : ${name} [options]
    options :
      --init        init a data file to enhance fix
      --force       force init or fix
      --target      target directory
      --fix         fix issues
      --fail-stop   stop process on first error
      --quiet       quiet mode
      --verbose     verbose mode
      -v --version  show version
      -h --help     show this help`)
  return { failed: [], passed: ['show-help'], warnings: [] }
}

const availableFlags = {
  '--fail-stop': Boolean,
  '--fix': Boolean,
  '--force': Boolean,
  '--help': Boolean,
  '--init': Boolean,
  '--quiet': Boolean,
  '--target': String,
  '--verbose': Boolean,
  '--version': Boolean,
  '-h': Boolean,
  '-v': Boolean,
}

type Flags = { readonly [Key in keyof typeof availableFlags]?: ReturnType<(typeof availableFlags)[Key]> }

export async function initDataFile(directoryPath = '', shouldForce = false) {
  const dataPath = join(directoryPath, dataFileName)
  const isPresent = await fileExists(dataPath)
  if (isPresent && !shouldForce) {
    log.warn('repo-checker data file', dataPath, 'already exists, use --force to overwrite it')
    return { failed: [], passed: [], warnings: ['data-file-already-exists'] }
  }
  const fileContent = await readFileInFolder(templatePath, dataFileName)
  void writeFile(dataPath, fileContent)
  log.info('repo-checker data file successfully init, you should edit :', dataPath)
  return { failed: [], passed: ['init-data-file'], warnings: [] }
}

export async function getData(directoryPath = '') {
  const dataPath = join(directoryPath, dataFileName)
  const isPresent = await fileExists(dataPath)
  if (!isPresent) {
    log.warn('you should use --init to prepare a data file to enhance fix')
    log.info('because no custom data file has been found, default data will be used')
    return dataDefaults
  }
  log.info('loading data from', dataPath)
  const { error, value } = parseJson<ProjectData>(await readFileInFolder(dataPath, ''))
  if (error) throw new Error(`error at getting data, target "${directoryPath}", dataPath "${dataPath}", error "${error}"`)
  return value
}

export const defaultOptions = {
  canFailStop: false,
  canFix: false,
  canForce: false,
  isQuiet: false,
  isVerbose: false,
  target: '.',
  willInit: false,
  willShowHelp: false,
  willShowVersion: false,
}

export function getFlags() {
  const sliceAfter = 2
  const flags = arg(availableFlags, { argv: process.argv.slice(sliceAfter) })
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
  return flags as Flags
}

// eslint-disable-next-line complexity
export function getOptions(flags: Flags) {
  return {
    canFailStop: flags['--fail-stop'] ?? defaultOptions.canFailStop,
    canFix: flags['--fix'] ?? defaultOptions.canFix,
    canForce: flags['--force'] ?? defaultOptions.canForce,
    isQuiet: flags['--quiet'] ?? defaultOptions.isQuiet,
    isVerbose: flags['--verbose'] ?? defaultOptions.isVerbose,
    target: getTarget(flags['--target']),
    willInit: flags['--init'] ?? defaultOptions.willInit,
    willShowHelp: flags['--help'] ?? flags['-h'] ?? defaultOptions.willShowHelp,
    willShowVersion: flags['--version'] ?? flags['-v'] ?? defaultOptions.willShowVersion,
  }
}

export async function start({ canFailStop, canFix, canForce, isQuiet, isVerbose, target, willInit, willShowHelp, willShowVersion }: Readonly<ReturnType<typeof getOptions>> = defaultOptions) {
  if (willShowVersion) return showVersion()
  if (willShowHelp) return showHelp()
  if (willInit) return await initDataFile(target, canForce)
  /* c8 ignore next 4 */
  const data = await getData(target)
  log.options.isActive = !isQuiet
  log.options.minimumLevel = isVerbose ? '1-debug' : '3-info'
  log.info(`${String(name)} __unique-mark__ is starting ${canFix ? '(fix enabled)' : ''}`)
  return await check({ canFailStop, canFix, canForce, data, folderPath: target })
}