diff options
Diffstat (limited to 'lib/config/index.js')
-rw-r--r-- | lib/config/index.js | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/lib/config/index.js b/lib/config/index.js new file mode 100644 index 0000000..7f75733 --- /dev/null +++ b/lib/config/index.js @@ -0,0 +1,132 @@ +var _ = require('lodash'); +var semver = require('semver'); + +var gitbook = require('../gitbook'); +var Promise = require('../utils/promise'); +var validator = require('./validator'); +var plugins = require('./plugins'); + +// Config files to tested (sorted) +var CONFIG_FILES = [ + 'book.js', + 'book.json' +]; + +/* +Config is an interface for the book's configuration stored in "book.json" (or "book.js") +*/ + +function Config(book, baseConfig) { + this.book = book; + this.fs = book.fs; + this.log = book.log; + this.path = ''; + + this.baseConfig = baseConfig || {}; + this.replace({}); +} + +// Load configuration of the book +// and verify that the configuration is satisfying +Config.prototype.load = function() { + var that = this; + var isLanguageBook = this.book.isLanguageBook(); + + // Try all potential configuration file + return Promise.some(CONFIG_FILES, function(filename) { + that.log.debug.ln('try loading configuration from', filename); + + return that.fs.loadAsObject(that.book.resolve(filename)) + .then(function(_config) { + that.log.debug.ln('configuration loaded from', filename); + + that.path = filename; + return that.replace(_config); + }) + .fail(function(err) { + if (err.code != 'MODULE_NOT_FOUND') throw(err); + else return Promise(false); + }); + }) + .then(function() { + if (!isLanguageBook) { + if (!gitbook.satisfies(that.options.gitbook)) { + throw new Error('GitBook version doesn\'t satisfy version required by the book: '+that.options.gitbook); + } + if (that.options.gitbook != '*' && !semver.satisfies(semver.inc(gitbook.version, 'patch'), that.options.gitbook)) { + that.log.warn.ln('gitbook version specified in your book.json might be too strict for future patches, \''+(_.first(gitbook.version.split('.'))+'.x.x')+'\' is more adequate'); + } + + that.options.plugins = plugins.toList(that.options.plugins); + } else { + // Multilingual book should inherits the plugins list from parent + that.options.plugins = that.book.parent.config.get('plugins'); + } + + that.options.gitbook = gitbook.version; + }); +}; + +// Replace the whole configuration +Config.prototype.replace = function(options) { + var that = this; + + // Extend base config + options = _.defaults(_.cloneDeep(options), this.baseConfig); + + // Validate the config + this.options = validator.validate(options); + + // options.input == book.root + Object.defineProperty(this.options, 'input', { + get: function () { + return that.book.root; + } + }); + + // options.originalInput == book.parent.root + Object.defineProperty(this.options, 'originalInput', { + get: function () { + return that.book.parent? that.book.parent.root : undefined; + } + }); +}; + +// Return true if book has a configuration file +Config.prototype.exists = function() { + return Boolean(this.path); +}; + +// Return path to a structure file +// Strip the extension by default +Config.prototype.getStructure = function(name, dontStripExt) { + var filename = this.options.structure[name]; + if (dontStripExt) return filename; + + filename = filename.split('.').slice(0, -1).join('.'); + return filename; +}; + +// Return a configuration using a key and a default value +Config.prototype.get = function(key, def) { + return _.get(this.options, key, def); +}; + +// Update a configuration +Config.prototype.set = function(key, value) { + return _.set(this.options, key, value); +}; + +// Return a dump of the configuration +Config.prototype.dump = function() { + return _.cloneDeep(this.options); +}; + +// Return templating context +Config.prototype.getContext = function() { + return { + config: this.book.config.dump() + }; +}; + +module.exports = Config; |