mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-16 23:55:20 +00:00
296 lines
8.7 KiB
JavaScript
296 lines
8.7 KiB
JavaScript
var _ = require('lodash');
|
||
var Q = require('q');
|
||
var fs = require('fs');
|
||
var path = require('path');
|
||
var semver = require('semver');
|
||
|
||
var pkg = require('../package.json');
|
||
var i18n = require('./utils/i18n');
|
||
|
||
// Default plugins added to each books
|
||
var DEFAULT_PLUGINS = ['highlight', 'search', 'sharing', 'fontsettings'];
|
||
|
||
// Check if a plugin is a default plugin
|
||
// Plugin should be in the list
|
||
// And version from book.json specified for this plugin should be satisfied
|
||
function isDefaultPlugin(name, version) {
|
||
if (!_.contains(DEFAULT_PLUGINS, name)) return false;
|
||
|
||
try {
|
||
var pluginPkg = require('gitbook-plugin-'+name+'/package.json');
|
||
return semver.satisfies(pluginPkg.version, version || '*');
|
||
} catch(e) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// Normalize a list of plugins to use
|
||
function normalizePluginsList(plugins, addDefaults) {
|
||
// Normalize list to an array
|
||
plugins = _.isString(plugins) ? plugins.split(',') : (plugins || []);
|
||
|
||
// Remove empty parts
|
||
plugins = _.compact(plugins);
|
||
|
||
// Divide as {name, version} to handle format like 'myplugin@1.0.0'
|
||
plugins = _.map(plugins, function(plugin) {
|
||
if (plugin.name) return plugin;
|
||
|
||
var parts = plugin.split('@');
|
||
var name = parts[0];
|
||
var version = parts[1];
|
||
return {
|
||
'name': name,
|
||
'version': version, // optional
|
||
'isDefault': isDefaultPlugin(name, version)
|
||
};
|
||
});
|
||
|
||
// List plugins to remove
|
||
var toremove = _.chain(plugins)
|
||
.filter(function(plugin) {
|
||
return plugin.name.length > 0 && plugin.name[0] == '-';
|
||
})
|
||
.map(function(plugin) {
|
||
return plugin.name.slice(1);
|
||
})
|
||
.value();
|
||
|
||
// Merge with defaults
|
||
if (addDefaults !== false) {
|
||
_.each(DEFAULT_PLUGINS, function(plugin) {
|
||
if (_.find(plugins, { name: plugin })) {
|
||
return;
|
||
}
|
||
|
||
plugins.push({
|
||
'name': plugin,
|
||
'isDefault': true
|
||
});
|
||
});
|
||
}
|
||
|
||
// Remove plugin that start with '-'
|
||
plugins = _.filter(plugins, function(plugin) {
|
||
return !_.contains(toremove, plugin.name) && !(plugin.name.length > 0 && plugin.name[0] == '-');
|
||
});
|
||
|
||
// Remove duplicates
|
||
plugins = _.uniq(plugins, 'name');
|
||
|
||
return plugins;
|
||
}
|
||
|
||
var Configuration = function(book, options) {
|
||
var that = this;
|
||
|
||
this.book = book;
|
||
|
||
this.options = _.cloneDeep(Configuration.DEFAULT);
|
||
this.options = _.merge(this.options, 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;
|
||
}
|
||
});
|
||
|
||
// options.originalOutput == book.parent.options.output
|
||
Object.defineProperty(this.options, 'originalOutput', {
|
||
get: function () {
|
||
return that.book.parent? that.book.parent.options.output : undefined;
|
||
}
|
||
});
|
||
};
|
||
|
||
// Read and parse the configuration
|
||
Configuration.prototype.load = function() {
|
||
var that = this;
|
||
|
||
return Q()
|
||
.then(function() {
|
||
var configPath, _config;
|
||
|
||
try {
|
||
configPath = require.resolve(
|
||
that.book.resolve(that.options.configFile)
|
||
);
|
||
|
||
// Invalidate node.js cache for livreloading
|
||
delete require.cache[configPath];
|
||
|
||
_config = require(configPath);
|
||
that.options = _.merge(
|
||
that.options,
|
||
_.omit(_config, 'configFile', 'defaultsPlugins', 'generator', 'extension')
|
||
);
|
||
}
|
||
catch(err) {
|
||
if (err instanceof SyntaxError) return Q.reject(err);
|
||
return Q();
|
||
}
|
||
})
|
||
.then(function() {
|
||
if (!that.book.isSubBook()) {
|
||
if (!semver.satisfies(pkg.version, 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(pkg.version, 'patch'), that.options.gitbook)) {
|
||
that.book.log.warn.ln('gitbook version specified in your book.json might be too strict for future patches, \''+(_.first(pkg.version.split('.'))+'.x.x')+'\' is more adequate');
|
||
}
|
||
}
|
||
|
||
that.options.output = path.resolve(that.options.output || that.book.resolve('_book'));
|
||
that.options.plugins = normalizePluginsList(that.options.plugins);
|
||
that.options.defaultsPlugins = normalizePluginsList(that.options.defaultsPlugins || '', false);
|
||
that.options.plugins = _.union(that.options.plugins, that.options.defaultsPlugins);
|
||
that.options.plugins = _.uniq(that.options.plugins, 'name');
|
||
|
||
// Default value for text direction (from language)
|
||
if (!that.options.direction) {
|
||
var lang = i18n.getCatalog(that.options.language);
|
||
if (lang) that.options.direction = lang.direction;
|
||
}
|
||
|
||
that.options.gitbook = pkg.version;
|
||
});
|
||
};
|
||
|
||
// Extend the configuration
|
||
Configuration.prototype.extend = function(options) {
|
||
_.extend(this.options, options);
|
||
};
|
||
|
||
// Get structure file
|
||
Configuration.prototype.getStructure = function(name) {
|
||
return this.options.structure[name].split('.').slice(0, -1).join('.');
|
||
};
|
||
|
||
// Return normalized language
|
||
Configuration.prototype.normalizeLanguage = function() {
|
||
return i18n.normalizeLanguage(this.options.language);
|
||
};
|
||
|
||
// Return a configuration
|
||
Configuration.prototype.get = function(key, def) {
|
||
return _.get(this.options, key, def);
|
||
};
|
||
|
||
// Default configuration
|
||
Configuration.DEFAULT = {
|
||
// Options that can't be extend
|
||
'configFile': 'book',
|
||
'generator': 'website',
|
||
'extension': null,
|
||
|
||
// Book metadats (somes are extracted from the README by default)
|
||
'title': null,
|
||
'description': null,
|
||
'isbn': null,
|
||
'language': 'en',
|
||
'direction': null,
|
||
'author': null,
|
||
|
||
// version of gitbook to use
|
||
'gitbook': '*',
|
||
|
||
// Structure
|
||
'structure': {
|
||
'langs': 'LANGS.md',
|
||
'readme': 'README.md',
|
||
'glossary': 'GLOSSARY.md',
|
||
'summary': 'SUMMARY.md'
|
||
},
|
||
|
||
// CSS Styles
|
||
'styles': {
|
||
'website': 'styles/website.css',
|
||
'print': 'styles/print.css',
|
||
'ebook': 'styles/ebook.css',
|
||
'pdf': 'styles/pdf.css',
|
||
'mobi': 'styles/mobi.css',
|
||
'epub': 'styles/epub.css'
|
||
},
|
||
|
||
// Plugins list, can contain '-name' for removing default plugins
|
||
'plugins': [],
|
||
|
||
// Global configuration for plugins
|
||
'pluginsConfig': {},
|
||
|
||
// Variables for templating
|
||
'variables': {},
|
||
|
||
// Set another theme with your own layout
|
||
// It's recommended to use plugins or add more options for default theme, though
|
||
// See https://github.com/GitbookIO/gitbook/issues/209
|
||
'theme': path.resolve(__dirname, '../theme'),
|
||
|
||
// Links in template (null: default, false: remove, string: new value)
|
||
'links': {
|
||
// Custom links at top of sidebar
|
||
'sidebar': {
|
||
// 'Custom link name': 'https://customlink.com'
|
||
},
|
||
|
||
// Sharing links
|
||
'sharing': {
|
||
'google': null,
|
||
'facebook': null,
|
||
'twitter': null,
|
||
'weibo': null,
|
||
'all': null
|
||
}
|
||
},
|
||
|
||
|
||
// Options for PDF generation
|
||
'pdf': {
|
||
// Add toc at the end of the file
|
||
'toc': true,
|
||
|
||
// Add page numbers to the bottom of every page
|
||
'pageNumbers': false,
|
||
|
||
// Font size for the file content
|
||
'fontSize': 12,
|
||
|
||
// Paper size for the pdf
|
||
// Choices are [u’a0’, u’a1’, u’a2’, u’a3’, u’a4’, u’a5’, u’a6’, u’b0’, u’b1’, u’b2’, u’b3’, u’b4’, u’b5’, u’b6’, u’legal’, u’letter’]
|
||
'paperSize': 'a4',
|
||
|
||
// How to mark detected chapters.
|
||
// Choices are “pagebreak”, “rule”, 'both' or “none”.
|
||
'chapterMark' : 'pagebreak',
|
||
|
||
// An XPath expression. Page breaks are inserted before the specified elements.
|
||
// To disable use the expression: '/'
|
||
'pageBreaksBefore': '/',
|
||
|
||
// Margin (in pts)
|
||
// Note: 72 pts equals 1 inch
|
||
'margin': {
|
||
'right': 62,
|
||
'left': 62,
|
||
'top': 56,
|
||
'bottom': 56
|
||
},
|
||
|
||
// Header HTML template. Available variables: _PAGENUM_, _TITLE_, _AUTHOR_ and _SECTION_.
|
||
'headerTemplate': null,
|
||
|
||
// Footer HTML template. Available variables: _PAGENUM_, _TITLE_, _AUTHOR_ and _SECTION_.
|
||
'footerTemplate': null
|
||
}
|
||
};
|
||
|
||
module.exports= Configuration;
|