Source: Component.js

'use strict'
/*
 * @preserve This file is part of "lassi-example".
 *    Copyright 2009-2014, arNuméral
 *    Author : Yoran Brault
 *    eMail  : yoran.brault@arnumeral.fr
 *    Site   : http://arnumeral.fr
 *
 * "lassi-example" is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * "lassi-example" is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with "lassi-example"; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

var Controller = require('./Controller')
var _ = require('lodash')
var log = require('an-log')('lassi-components')

/**
 * Construction d'un composant.
 * Ce constructeur n'est jamais appelé directement. Utilisez {@link Lassi#component}
 * @constructor
 * @param {string} name Le nom du composant.
 * @param {string[]} dependencies Noms des composants dont celui-ci dépend
 */
class Component {
  constructor (name, dependencies) {
    if (lassi.options.cli) log.setLogLevel('warning')
    if (dependencies && !Array.isArray(dependencies)) throw new Error('Component dependencies should be an Array of components names')
    this.name = name
    this.controllers = []
    this.dependencies = dependencies || []
    this.entities = {}
    this.services = {}
    this.path = undefined
    this.userConfig = []
  }

  /**
   * Ajoute un configurateur au composant.
   * @param {Function} fn le configurateur.
   * @return {Component} chaînable
   */
  config (fn) {
    this.userConfig.push(fn)
    return this
  }

  /**
   * Configuration du composant
   */
  configure () {
    // Si on est déjà configuré, on repart
    if (this.configured) return

    log('configure', this.name)
    var self = this
    _.forEach(self.dependencies, dependency => lassi.components[dependency].configure())
    _.forEach(self.services, (service, name) => lassi.services.register(name, service))
    _.forEach(self.entities, function (entity, name) {
      // on est dans un each, faut une iife pour préserver le (entity, name) courant
      const serviceConstructor = (function (name, entity) {
        return function ($entities) {
          var def = $entities.define(name)
          lassi.services.parseInjections(entity, def)
          return def
        }
      })(name, entity)
      lassi.services.register(name, serviceConstructor)
    })
    if (!lassi.options.cli) {
      _.forEach(self.controllers, function (fn, name) {
        var controller = new Controller(fn.$$path)
        lassi.services.parseInjections(fn, controller)
        self.controllers[name] = controller
      })
    }

    _.forEach(self.userConfig, function (userConfig) {
      lassi.services.parseInjections(userConfig, self)
    })
    this.configured = true
    log('configured', this.name)
  }

  /**
   * Définition d'un controleur dans le composant.
   * @param {String} [path] le chemin des actions de ce contrôleur.
   * @param {function} fn La fonction du controleur.
   * @return {Component} chaînable
   */
  controller (path, fn) {
    if (typeof path === 'function') {
      fn = path
      path = undefined
    }
    fn.$$path = path
    this.controllers.push(fn)
    return this
  }

  /**
   * Ajoute une {@link EntityDefinition} au composant.
   * @param {String} name le nom de l'entité.
   * @param {Function} fn La fonction de l'entité
   * @return {Component} chaînable
   */
  entity (name, fn) {
    this.entities[name] = fn
    return this
  }

  /**
   * Définition d'un service.
   * @param String name Le nom du service.
   * @param function name Le service (paramètres injectables).
   * @return Lassi chaînable
   */
  service (name, fn) {
    this.services[name] = fn
    return this
  }

  /**
   * Démarre l'application.
   * @fires Lassi#bootstrap
   */
  bootstrap (cb) {
    lassi.bootstrap(this, cb)
  }
}

module.exports = Component