blot
Version:
The DRY documentation builder
192 lines (166 loc) • 5.44 kB
JavaScript
import * as fsConfig from 'config.json'
import hazy from 'hazy'
import fs from 'fs'
import path from 'path'
import {util} from './io'
import isPlainObject from 'lodash.isplainobject'
let enviros = {}
let selected = null
/**
* Project environment configuration.
* Binds certain data to fixture pool
* so it can be accessed in documentation.
*/
export class Config {
/**
* @param {String} name key-friendly name of the environment
* @param {String} source path of original configuration project file
* @param {String} base base path for all other paths in blot
* @param {String} host API host (for use in docs)
* @param {String} docs I/O configuration for docs
* @param {String} fixtures I/O configuration for fixtures
* @param {String} logging whether or not to print standardized logs
* @param {String} pretty whether ot not to print pretty logs
*/
constructor(name, source, base, host, docs, fixtures, view, echo = false, logging = false, pretty = false) {
this.source = source
this.name = name || 'root'
this.base = base || '.'
this.host = host || '127.0.0.1'
this.docs = docs || {src: '', dest: '', export: false}
this.fixtures = fixtures || {src: '', dest: '', export: false}
this.view = view || {dest: '', export: false, theme: {}, elements: {}, attrs: {}}
this.echo = echo
this.logging = logging
this.pretty = pretty
enviros[source || name] = this
}
/**
* Adjusts provided filepath to be project/environment-specific
*
* @param {String} filepath
* @returns {String} filepath adjusted to project base path
*/
uri(filepath: String): String {
return path.resolve(`${this.base}/${filepath}`)
}
/**
* Provides the expected root file URI for project config
*
* @param {String} filepath
* @returns {String} filepath adjusted to project base path
*/
get rootUri(): String {
return this.source || Config.rootUri(this.name)
}
/**
* Determines whether a blot project file configuration exists
* or a filepath source has been defined.
*
* @returns {Boolean}
*/
get isProject(): Boolean {
return this.source || util.fs.existsAt(this.rootUri)
}
/**
* Determines the expected root file URI for project environment config
*
* @param {String} env environment name
* @returns {String} filepath adjusted to project environment config
*/
static rootUri(env: String): String {
return (env && env !== 'root') ? env : `./blot.json`
}
/**
* Determines if a blot project file configuration exists for enviro
*
* @returns {Boolean}
*/
static isProject(env?: String): Boolean {
return util.fs.existsAt(Config.rootUri(env))
}
/**
* Loads a blot project configuration file and parses it
*
* @param {String} filepath
* @returns {Promise}
*/
static src(filepath: String): Promise {
return new Promise((resolve, reject) => {
const envPath = path.resolve(filepath || Config.rootUri())
return fs.readFile(envPath, 'utf-8', (err, data) => {
if (!err) {
resolve(
configure(
Object.assign(JSON.parse(data), {source: filepath})
)
)
} else {
reject(`Failed to read in blot environment configuration from ${path}`)
}
})
})
}
/**
* Loads a blot project configuration file, parses it and then
* establishes it as the selected environment
*
* @param {String} envPath environment filepath
* @param {String} project configuration overrides (typically from CLI)
* @returns {Promise}
*/
static loadProject(envPath: String, options: Object, chdir: Boolean = false): Promise {
return new Promise((resolve, reject) => {
Config
.src(Config.rootUri(envPath))
.then(project => {
// override project config with options (typically CLI) when necessary
if (options) {
if (project) {
Object.assign(project, options)
} else {
project = options
}
}
use(project, chdir)
resolve(project)
})
.catch(reject)
})
}
}
/**
* Bootstraps and establishes a project environment as the default
*
* @param {Config|Object} env
* @returns {Promise}
*/
export function use(project: Config, chdir: Boolean = false) {
if (project instanceof Config || isPlainObject(config)) {
selected = project.source || project.name
enviros[selected] = project
const usefuls = ['name', 'host', 'base', 'docs', 'fixtures']
// register certain useful config objects with hazy for easy access
usefuls.forEach(prop =>
hazy.fixture.register(`blot.config.${prop}`, project[prop])
)
if (project.source && chdir) {
process.chdir(path.dirname(project.source))
}
}
return project
}
/**
* Destructured alias for instantiating environment / project Configs
*
* @param {Object} arguments configuration object
* @returns {Config}
*/
export const configure = ({name, source, base, host, docs, fixtures, view, echo, logging, pretty}) => new Config(name, source, base, host, docs, fixtures, view, echo, logging, pretty)
/**
* Provides the currently selected environment in blot
*
* @returns {Config|Object}
*/
export const current = () => enviros[selected] || {}