All files / src/class compiler.ts

74.36% Statements 29/39
53.85% Branches 7/13
90% Functions 9/10
79.41% Lines 27/34

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 925x 5x 5x 5x   5x 5x 5x                                   5x     8x   8x     8x 8x   16x       21x       10x       13x       5x 5x   5x         5x                           5x   5x 5x   5x       3x       5x 5x      
import fs from 'fs-extra'
import EventEmitter from 'events'
import { mergeDeepLeft, pick, prop } from 'ramda'
import { join } from 'path'
import { CheckOptions, Prompter, Resource } from '@/internal'
import { inquirerPrompter } from '@/prompters'
import yaml from 'js-yaml'
import { logger } from '@/utils'
import { Template } from './template'
import { Project } from './project'
 
 
export interface CompilerOptions {
  prompter?: Prompter
}
 
export interface RenderOptions {
  /**
   * always prompt the question,
   * even though it was answered.
   */
  ignoreAnswered?: boolean
}
 
 
export class Compiler {
  public readonly resource: Resource
 
  private readonly eventEmitter: EventEmitter = new EventEmitter()
 
  private readonly prompter: Prompter = inquirerPrompter
 
  constructor(resource: Resource, options: CompilerOptions = {}) {
    this.resource = resource
    Iif (options.prompter) this.prompter = options.prompter
 
    this.template.hooks.map(hook => hook.appendTo(this.eventEmitter))
  }
 
  get template(): Template {
    return this.resource.template
  }
 
  get project(): Project {
    return this.resource.project
  }
 
  public emit(name: string): void {
    this.eventEmitter.emit(name)
  }
 
  private async prompt(force = false): Promise<void> {
    const { template, project, prompter } = this
    let { questions } = template
 
    Iif (project.answers && !force) {
      const answers = project.answers
      questions = questions.filter(question => !question.answered(answers))
    }
 
    Eif (!questions.length) return
 
    logger.info('Please answer the questions of template.')
 
    const namesOfQuestions = questions.map(prop('name'))
    let answers = await prompter(questions)
 
    if (project.answers) answers = mergeDeepLeft(answers, project.answers)
 
 
    project.answers = pick(namesOfQuestions, answers)
  }
 
  public async render(options: RenderOptions = {}): Promise<void> {
    await this.prompt(options.ignoreAnswered)
 
    await this.template.render(this.resource)
    await this.generateMilirc()
 
    this.emit('rendered')
  }
 
  public async check(options: CheckOptions): Promise<void> {
    await this.template.check(this.resource, options)
  }
 
  private async generateMilirc(): Promise<void> {
    const milirc = yaml.safeDump(this.resource.milirc, { skipInvalid: true })
    await fs.writeFile(join(this.project.path, '.milirc.yml'), milirc, 'utf8')
  }
}