All files / src/class question.ts

80.65% Statements 50/62
73.47% Branches 36/49
100% Functions 6/6
95.12% Lines 39/41

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 10815x                                                           15x 5x   5x   5x       5x   5x   5x   5x   5x   5x   5x   5x     5x 5x   5x 5x 5x 5x 5x 5x 5x 5x 5x 5x       5x 5x   5x 14x   8x 8x         11x 11x   8x   8x 7x 5x 3x 4x                            
import { identity, T } from 'ramda'
type QuesstionTypes = 'input' | 'confirm' | 'number' | 'list' | 'rawlist' | 'expand' | 'checkbox' | 'password' | 'editor'
type Validator = (input: string) => boolean | string
type Choice = string | number | boolean | DetailedChoice
type Choices = ((answers: Answers) => Choice[]) | Choice[]
type Filter = <T>(value: T) => T
type When = (answers: Answers) => boolean
 
interface DetailedChoice {
  name: string
  value: string | number | boolean
  checked?: boolean
  disabled?: boolean
}
 
export interface QuestionOptions {
  type?: QuesstionTypes
  name: string
  message?: string | Function
  default?: any
  choices?: Choices
  validate?: Validator
  filter?: Filter
  transformer?: Function
  when?: When
  pageSize?: number
  prefix?: string
  suffix?: string
}
 
export class Question {
  public type: QuesstionTypes = 'input'
 
  public name: string = ''
 
  public message: string | Function = ''
 
  public default: any
 
  public choices: Choices = []
 
  public validate: Validator = T
 
  public filter: Filter = identity
 
  public transformer: Function = identity
 
  public when: When = T
 
  public pageSize: number = 0
 
  public prefix: string = ''
 
  public suffix: string = ''
 
  constructor(options: QuestionOptions) {
    if (options.type) this.type = options.type
    Eif (options.name) this.name = options.name
    else throw new TypeError('name should not be empty')
    Iif (options.message) this.message = options.message
    Iif (options.default) this.default = options.default
    if (options.choices) this.choices = options.choices
    Iif (options.validate) this.validate = options.validate
    Iif (options.filter) this.filter = options.filter
    Iif (options.transformer) this.transformer = options.transformer
    Iif (options.when) this.when = options.when
    Iif (options.pageSize) this.pageSize = options.pageSize
    Iif (options.prefix) this.prefix = options.prefix
    Iif (options.suffix) this.suffix = options.suffix
  }
 
  private includesByChoices(value, answers: Answers): boolean {
    let choices = this.choices
    if (typeof choices === 'function') choices = choices(answers)
 
    return choices
      .filter(choice => typeof choice !== 'object' || !choice.disabled)
      .some(choice => {
        Iif (typeof choice === 'object') return choice.value === value
        return choice === value
      })
  }
 
  public answered(answers: Answers): boolean {
    const { name, type } = this
    if (!Object.keys(answers).includes(name)) return false
 
    const answer = answers[name]
 
    if (type === 'input' || type === 'password') return typeof answer === 'string'
    if (type === 'number') return typeof answer === 'number'
    if (type === 'confirm') return typeof answer === 'boolean'
    if (type === 'list' || type === 'rawlist' || type === 'expand') return this.includesByChoices(answer, answers)
    Eif (type === 'checkbox' && Array.isArray(answer)) return answer.every(value => this.includesByChoices(value, answers))
 
    return false
  }
}
 
export type Questions = Question[]
 
export interface Answers {
  [name: string]: string | number | boolean | (string | number)[]
}
 
export type Prompter = (question: Question[]) => Promise<Answers>