CollectionItem.js

const yaml = require('js-yaml')
const { verifyRequired } = require('@bowtie/utils')

const Base = require('./Base')

/**
 * CollectionItem class
 */
class CollectionItem extends Base {
  /**
   * Create a new CollectionItem object
   *
   * @constructor
   * @param {Object} options - Options to create this CollectionItem
   * @param {Object} options.collection - Collection for this CollectionItem
   * @param {String} options.name - Name for this CollectionItem
   * @param {String} options.path - Path for this CollectionItem
   */
  constructor (options = {}) {
    verifyRequired(options, [ 'collection', 'name', 'path' ])

    super(options)

    this.jekyll = this.collection.jekyll
    this.github = this.jekyll.github
    this.repoPath = this.jekyll.repoPath
    this.repoParams = this.jekyll.repoParams
    this.defaultParams = Object.assign({}, this.repoParams, {
      path: this.path,
      sha: this.sha
    })
  }

  /**
   * Initialize this collection item
   * Load fields and content and save to itself
   *
   * @param {Object} [params] - Additional params (sent to github)
   * @returns {Promise<CollectionItem>} - Returns promise with itself
   */
  init (params = {}) {
    return this.defaults(params).then(defaults => {
      this.fields = defaults['fields']
      this.body = defaults['body']

      return Promise.resolve(this)
    })
  }

  /**
   * Reload this collection item (update attributes & sha)
   *
   * @param {Object} [params] - Additional params (sent to github)
   * @returns {Promise<CollectionItem>} - Returns promise with itself
   */
  reload (params = {}) {
    return new Promise(
      (resolve, reject) => {
        this.logger.info(`Reloading collection item: ${this.path}`)

        if (params['content']) {
          delete params['content']
        }

        this.github.files(this._params(params)).then(({ file }) => {
          Object.assign(this, file)

          Object.assign(this.defaultParams, {
            sha: this.sha
          })

          resolve(this)
        }).catch(reject)
      }
    )
  }

  /**
   * Get defaults (current fields & body) for this collection item
   *
   * @param {Object} [params] - Additional params (sent to github)
   * @returns {Promise<Object>} - Returns promise with defaults
   */
  defaults (params = {}) {
    return this.collection.parsePath(this.path, params)
  }

  /**
   * Get specific default key for this collection item
   *
   * @param {String} key - Key for default to get (fields or body)
   * @param {Object} [params] - Additional params (sent to github)
   * @returns {Promise<Object|String>} - Returns promise with requested default key data
   */
  defaultsKey (key, params = {}) {
    return this.defaults(params).then(defaults => {
      return Promise.resolve(defaults[key])
    })
  }

  /**
   * Transform this CollectionItem into base64 content (to be sent to github)
   *
   * @param {Object} [params] - Additional params (sent to github)
   * @returns {String} - Returns base64 encoded string of Jekyll style file content
   */
  contentBase64 (params = {}) {
    const fields = this.fields || {}
    const body = this.body || ''

    return Buffer.from(`---\n${yaml.safeDump(fields)}\n---\n${body}\n`).toString('base64')
  }

  // loadContent (params = {}) {
  //   return this.defaultsKey('body', params)
  // }

  // loadFields (params = {}) {
  //   return this.defaultsKey('fields', params)
  // }

  /**
   * Save this CollectionItem
   *
   * @param {Object} [params] - Additional params (sent to github)
   * @returns {Promise<CollectionItem>} - Returns promise with itself
   */
  save (params = {}) {
    params['content'] = this.contentBase64(params)

    if (params['ref'] && !params['branch']) {
      params['branch'] = params['ref']
    }

    const githubAction = this.sha ? 'updateFile' : 'createFile'

    return this.github[githubAction](this._params(params)).then(resp => {
      this.logger.info('Updated item file: ' + this.path)
      this.collection.clearCache(this.path)

      return this.reload(params)
    })
  }

  /**
   * Delete this CollectionItem
   *
   * @param {Object} [params] - Additional params (sent to github)
   * @returns {Promise<CollectionItem>} - Returns promise with itself
   */
  delete (params = {}) {
    if (params['ref'] && !params['branch']) {
      params['branch'] = params['ref']
    }

    return this.github.deleteFile(this._params(params)).then(resp => {
      this.logger.info('Deleted item file: ' + this.path)
      this.collection.clearCache(this.path)

      return Promise.resolve(this)
    })
  }

  /**
   * Rename this CollectionItem
   *
   * @param {String} name - New name for this item
   * @param {Object} [params] - Additional params (sent to github)
   * @returns {Promise<CollectionItem>} - Returns promise with itself
   */
  rename (name, params = {}) {
    return this.delete(params).then(() => {
      const { fields, body } = this

      return this.collection.createItem({
        name,
        fields,
        body
      }, params).then(item => {
        Object.assign(this, item)
        return Promise.resolve(this)
      })
    })
  }
}

module.exports = CollectionItem