Manual Reference Source Test

src/PopApi.js

// Import the necessary modules.
// @flow
import debug from 'debug'
/**
 * Fast, unopinionated, minimalist web framework for node.
 * @external {Express} https://github.com/expressjs/express
 */
import express, { type $Application } from 'express'
import { isMaster } from 'cluster'
import { join } from 'path'

import {
  Cli,
  Database,
  HttpServer,
  Logger,
  Routes
} from './middleware'
import * as utils from './utils'
import { name } from '../package.json'

/**
 * The default log directory.
 * @type {string}
 */
const defaultLogDir = join(...[
  __dirname,
  '..',
  'tmp'
])

/**
 * The PopApi class with the middleware pattern.
 * @type {PopApi}
 */
export default class PopApi {

  /**
   * The database connection.
   * @type {Database}
   */
  static database: Database

  /**
   * The arguments passed down to the logger middleware.
   * @type {Object}
   */
  static loggerArgs: Object

  /**
   * The application instance for the PopApi framework.
   * @type {Express}
   */
  static app: $Application = express()

  /**
   * The debugger for extra  output.
   * @type {Function}
   */
  static debug: Function = debug(name)

  /**
   * A map of the installed plugins.
   * @type {Map<any>}
   */
  static _installedPlugins: Map<string, any> = new Map()

  /**
   * The setup for the base framework.
   * @param {!Object} options - The options for the framework.
   * @param {!Express} [options.app=PopApi.app] - The web framework instance you
   * want to use.
   * @param {!Array<Object>} options.controllers - The controllers to register.
   * @param {!string} options.name - The name for your API.
   * @param {!string} options.version - The version of your API.
   * @param {?string} options.logDir - The directory to store the log files in.
   * @param {?Array<string>} [options.hosts] - The hosts of
   * the database cluster.
   * @param {?number} [options.dbPort] - The port the database is on.
   * @param {?string} [options.username] - The username for the database
   * connection.
   * @param {?string} [options.password] - The password for the database
   * connection.
   * @param {?number} [options.serverPort] - The port the API will run on.
   * @param {?number} [options.workers] - The number of workers for the API.
   * @param {?Object} [options.opts] - Additionl options for custom
   * middlewares.
   * @param {!Array<Function>} middlewares - The list of middlewares to use.
   * The order of the middlewares is important.
   * @returns {Promise<PopApi, Error>} - The initialized PopApi instance.
   */
  static async init({
    app = PopApi.app,
    controllers,
    name,
    version,
    logDir = defaultLogDir,
    hosts,
    dbPort,
    username,
    password,
    serverPort,
    workers,
    ...opts
  }: Object, middlewares: Array<Function> = [
    Cli,
    Logger,
    Database,
    Routes,
    HttpServer
  ]): Promise<Object | Error> {
    PopApi.app = app
    if (isMaster) {
      await utils.createTemp(logDir)
    }

    middlewares.map(Middleware => {
      PopApi.use(Middleware, {
        app,
        controllers,
        name,
        version,
        logDir,
        database: name,
        hosts,
        dbPort,
        username,
        password,
        serverPort,
        workers,
        argv: process.argv,
        ...PopApi.loggerArgs,
        ...opts
      })
    })
    await PopApi.database.connect()

    return PopApi
  }

  /**
   * Register middleware for the PopApi framework.
   * @param {!Function} Plugin - The plugin to use.
   * @param {!Object} args - The arguments passed down to the constructor of
   * the plugin.
   * @returns {Promise<PopApi>} - The PopApi instance with the installed
   * plugins.
   */
  static use(Plugin: any, ...args: any): any {
    if (PopApi._installedPlugins.has(Plugin)) {
      return this
    }

    const plugin = typeof Plugin === 'function'
      ? new Plugin(this, ...args)
      : null

    if (plugin) {
      PopApi._installedPlugins.set(Plugin, plugin)
    }

    return this
  }

}