mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-28 13:08:57 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 257158321c | |||
| ddf0a41e29 | |||
| 357e1e8e96 | |||
| 7a89f9869a | |||
| 30fbd22efe | |||
| 29df73ba72 | |||
| f8676483c1 | |||
| c79a6f2fba | |||
| c38e67ea61 | |||
| 97a5f8805e | |||
| 421fef6ebf | |||
| 33406c3082 | |||
| c3851889b0 | |||
| 4a5de2da6b | |||
| 1afb23cada | |||
| a3b0f3f868 | |||
| 0aa32916d6 |
@@ -2,6 +2,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 3.1.0
|
||||
- Always load themes after plugins
|
||||
- README/Introduction doesn't require to be the first entry in the summary
|
||||
- Highlight active entry in summary when scrolling a page with anchors
|
||||
- Support empty parts in summary
|
||||
|
||||
## 3.0.3
|
||||
- Fix redirection in `gitbook serve` when accessing a folder without trailing slash
|
||||
- Fix links/annotations for glossary not being correctly resolved
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/*
|
||||
All GitBook themes plugins name start with this prefix once shorted.
|
||||
*/
|
||||
module.exports = 'theme-';
|
||||
+27
-6
@@ -293,26 +293,47 @@ Book.prototype.getDefaultExt = function() {
|
||||
|
||||
/**
|
||||
Infer the default path for a Readme.
|
||||
@param {Boolean} [absolute=false] False for a path relative to
|
||||
this book's content root
|
||||
@return {String}
|
||||
*/
|
||||
Book.prototype.getDefaultReadmePath = function() {
|
||||
return this.getContentRoot()+'README'+this.getDefaultExt();
|
||||
Book.prototype.getDefaultReadmePath = function(absolute) {
|
||||
var defaultPath = 'README'+this.getDefaultExt();
|
||||
if (absolute) {
|
||||
return path.join(this.getContentRoot(), defaultPath);
|
||||
} else {
|
||||
return defaultPath;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Infer the default path for a Summary.
|
||||
@param {Boolean} [absolute=false] False for a path relative to
|
||||
this book's content root
|
||||
@return {String}
|
||||
*/
|
||||
Book.prototype.getDefaultSummaryPath = function() {
|
||||
return this.getContentRoot()+'SUMMARY'+this.getDefaultExt();
|
||||
Book.prototype.getDefaultSummaryPath = function(absolute) {
|
||||
var defaultPath = 'SUMMARY'+this.getDefaultExt();
|
||||
if (absolute) {
|
||||
return path.join(this.getContentRoot(), defaultPath);
|
||||
} else {
|
||||
return defaultPath;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Infer the default path for a Glossary.
|
||||
@param {Boolean} [absolute=false] False for a path relative to
|
||||
this book's content root
|
||||
@return {String}
|
||||
*/
|
||||
Book.prototype.getDefaultGlossaryPath = function() {
|
||||
return this.getContentRoot()+'GLOSSARY'+this.getDefaultExt();
|
||||
Book.prototype.getDefaultGlossaryPath = function(absolute) {
|
||||
var defaultPath = 'GLOSSARY'+this.getDefaultExt();
|
||||
if (absolute) {
|
||||
return path.join(this.getContentRoot(), defaultPath);
|
||||
} else {
|
||||
return defaultPath;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+53
-56
@@ -19,21 +19,27 @@ Config.prototype.getValues = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
Change the file for the configuration
|
||||
* Render config as text
|
||||
* @return {Promise<String>}
|
||||
*/
|
||||
Config.prototype.toText = function() {
|
||||
return JSON.stringify(this.getValues().toJS(), null, 4);
|
||||
};
|
||||
|
||||
@param {File} file
|
||||
@return {Config}
|
||||
*/
|
||||
/**
|
||||
* Change the file for the configuration
|
||||
* @param {File} file
|
||||
* @return {Config}
|
||||
*/
|
||||
Config.prototype.setFile = function(file) {
|
||||
return this.set('file', file);
|
||||
};
|
||||
|
||||
/**
|
||||
Return a configuration value by its key path
|
||||
|
||||
@param {String} key
|
||||
@return {Mixed}
|
||||
*/
|
||||
* Return a configuration value by its key path
|
||||
* @param {String} key
|
||||
* @return {Mixed}
|
||||
*/
|
||||
Config.prototype.getValue = function(keyPath, def) {
|
||||
var values = this.getValues();
|
||||
keyPath = Config.keyToKeyPath(keyPath);
|
||||
@@ -46,12 +52,11 @@ Config.prototype.getValue = function(keyPath, def) {
|
||||
};
|
||||
|
||||
/**
|
||||
Update a configuration value
|
||||
|
||||
@param {String} key
|
||||
@param {Mixed} value
|
||||
@return {Config}
|
||||
*/
|
||||
* Update a configuration value
|
||||
* @param {String} key
|
||||
* @param {Mixed} value
|
||||
* @return {Config}
|
||||
*/
|
||||
Config.prototype.setValue = function(keyPath, value) {
|
||||
keyPath = Config.keyToKeyPath(keyPath);
|
||||
|
||||
@@ -64,10 +69,9 @@ Config.prototype.setValue = function(keyPath, value) {
|
||||
};
|
||||
|
||||
/**
|
||||
Return a list of plugin dependencies
|
||||
|
||||
@return {List<PluginDependency>}
|
||||
*/
|
||||
* Return a list of plugin dependencies
|
||||
* @return {List<PluginDependency>}
|
||||
*/
|
||||
Config.prototype.getPluginDependencies = function() {
|
||||
var plugins = this.getValue('plugins');
|
||||
|
||||
@@ -79,11 +83,10 @@ Config.prototype.getPluginDependencies = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
Return a plugin dependency by its name
|
||||
|
||||
@param {String} name
|
||||
@return {PluginDependency}
|
||||
*/
|
||||
* Return a plugin dependency by its name
|
||||
* @param {String} name
|
||||
* @return {PluginDependency}
|
||||
*/
|
||||
Config.prototype.getPluginDependency = function(name) {
|
||||
var plugins = this.getPluginDependencies();
|
||||
|
||||
@@ -93,11 +96,10 @@ Config.prototype.getPluginDependency = function(name) {
|
||||
};
|
||||
|
||||
/**
|
||||
Update the list of plugins dependencies
|
||||
|
||||
@param {List<PluginDependency>}
|
||||
@return {Config}
|
||||
*/
|
||||
* Update the list of plugins dependencies
|
||||
* @param {List<PluginDependency>}
|
||||
* @return {Config}
|
||||
*/
|
||||
Config.prototype.setPluginDependencies = function(deps) {
|
||||
var plugins = PluginDependency.listToArray(deps);
|
||||
|
||||
@@ -106,11 +108,10 @@ Config.prototype.setPluginDependencies = function(deps) {
|
||||
|
||||
|
||||
/**
|
||||
Update values for an existing configuration
|
||||
|
||||
@param {Object} values
|
||||
@returns {Config}
|
||||
*/
|
||||
* Update values for an existing configuration
|
||||
* @param {Object} values
|
||||
* @returns {Config}
|
||||
*/
|
||||
Config.prototype.updateValues = function(values) {
|
||||
values = Immutable.fromJS(values);
|
||||
|
||||
@@ -118,12 +119,11 @@ Config.prototype.updateValues = function(values) {
|
||||
};
|
||||
|
||||
/**
|
||||
Update values for an existing configuration
|
||||
|
||||
@param {Config} config
|
||||
@param {Object} values
|
||||
@returns {Config}
|
||||
*/
|
||||
* Update values for an existing configuration
|
||||
* @param {Config} config
|
||||
* @param {Object} values
|
||||
* @returns {Config}
|
||||
*/
|
||||
Config.prototype.mergeValues = function(values) {
|
||||
var currentValues = this.getValues();
|
||||
values = Immutable.fromJS(values);
|
||||
@@ -134,12 +134,11 @@ Config.prototype.mergeValues = function(values) {
|
||||
};
|
||||
|
||||
/**
|
||||
Create a new config for a file
|
||||
|
||||
@param {File} file
|
||||
@param {Object} values
|
||||
@returns {Config}
|
||||
*/
|
||||
* Create a new config for a file
|
||||
* @param {File} file
|
||||
* @param {Object} values
|
||||
* @returns {Config}
|
||||
*/
|
||||
Config.create = function(file, values) {
|
||||
return new Config({
|
||||
file: file,
|
||||
@@ -148,11 +147,10 @@ Config.create = function(file, values) {
|
||||
};
|
||||
|
||||
/**
|
||||
Create a new config
|
||||
|
||||
@param {Object} values
|
||||
@returns {Config}
|
||||
*/
|
||||
* Create a new config
|
||||
* @param {Object} values
|
||||
* @returns {Config}
|
||||
*/
|
||||
Config.createWithValues = function(values) {
|
||||
return new Config({
|
||||
values: Immutable.fromJS(values)
|
||||
@@ -161,11 +159,10 @@ Config.createWithValues = function(values) {
|
||||
|
||||
|
||||
/**
|
||||
Convert a keyPath to an array of keys
|
||||
|
||||
@param {String|Array}
|
||||
@return {Array}
|
||||
*/
|
||||
* Convert a keyPath to an array of keys
|
||||
* @param {String|Array}
|
||||
* @return {Array}
|
||||
*/
|
||||
Config.keyToKeyPath = function(keyPath) {
|
||||
if (is.string(keyPath)) keyPath = keyPath.split('.');
|
||||
return keyPath;
|
||||
|
||||
@@ -6,9 +6,9 @@ var PREFIX = require('../constants/pluginPrefix');
|
||||
var DEFAULT_VERSION = '*';
|
||||
|
||||
/*
|
||||
PluginDependency represents the informations about a plugin
|
||||
stored in config.plugins
|
||||
*/
|
||||
* PluginDependency represents the informations about a plugin
|
||||
* stored in config.plugins
|
||||
*/
|
||||
var PluginDependency = Immutable.Record({
|
||||
name: String(),
|
||||
|
||||
@@ -32,29 +32,39 @@ PluginDependency.prototype.isEnabled = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
Return NPM ID for the dependency
|
||||
* Toggle this plugin state
|
||||
* @param {Boolean}
|
||||
* @return {PluginDependency}
|
||||
*/
|
||||
PluginDependency.prototype.toggle = function(state) {
|
||||
if (is.undef(state)) {
|
||||
state = !this.isEnabled();
|
||||
}
|
||||
|
||||
@return {String}
|
||||
*/
|
||||
return this.set('enabled', state);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return NPM ID for the dependency
|
||||
* @return {String}
|
||||
*/
|
||||
PluginDependency.prototype.getNpmID = function() {
|
||||
return PluginDependency.nameToNpmID(this.getName());
|
||||
};
|
||||
|
||||
/**
|
||||
Is the plugin using a git dependency
|
||||
|
||||
@return {Boolean}
|
||||
*/
|
||||
* Is the plugin using a git dependency
|
||||
* @return {Boolean}
|
||||
*/
|
||||
PluginDependency.prototype.isGitDependency = function() {
|
||||
return !semver.validRange(this.getVersion());
|
||||
};
|
||||
|
||||
/**
|
||||
Create a plugin with a name and a plugin
|
||||
|
||||
@param {String}
|
||||
@return {Plugin|undefined}
|
||||
*/
|
||||
* Create a plugin with a name and a plugin
|
||||
* @param {String}
|
||||
* @return {Plugin|undefined}
|
||||
*/
|
||||
PluginDependency.create = function(name, version, enabled) {
|
||||
if (is.undefined(enabled)) {
|
||||
enabled = true;
|
||||
@@ -68,11 +78,10 @@ PluginDependency.create = function(name, version, enabled) {
|
||||
};
|
||||
|
||||
/**
|
||||
Create a plugin from a string
|
||||
|
||||
@param {String}
|
||||
@return {Plugin|undefined}
|
||||
*/
|
||||
* Create a plugin from a string
|
||||
* @param {String}
|
||||
* @return {Plugin|undefined}
|
||||
*/
|
||||
PluginDependency.createFromString = function(s) {
|
||||
var parts = s.split('@');
|
||||
var name = parts[0];
|
||||
@@ -92,22 +101,20 @@ PluginDependency.createFromString = function(s) {
|
||||
};
|
||||
|
||||
/**
|
||||
Create a PluginDependency from a string
|
||||
|
||||
@param {String}
|
||||
@return {List<PluginDependency>}
|
||||
*/
|
||||
* Create a PluginDependency from a string
|
||||
* @param {String}
|
||||
* @return {List<PluginDependency>}
|
||||
*/
|
||||
PluginDependency.listFromString = function(s) {
|
||||
var parts = s.split(',');
|
||||
return PluginDependency.listFromArray(parts);
|
||||
};
|
||||
|
||||
/**
|
||||
Create a PluginDependency from an array
|
||||
|
||||
@param {Array}
|
||||
@return {List<PluginDependency>}
|
||||
*/
|
||||
* Create a PluginDependency from an array
|
||||
* @param {Array}
|
||||
* @return {List<PluginDependency>}
|
||||
*/
|
||||
PluginDependency.listFromArray = function(arr) {
|
||||
return Immutable.List(arr)
|
||||
.map(function(entry) {
|
||||
@@ -126,11 +133,10 @@ PluginDependency.listFromArray = function(arr) {
|
||||
};
|
||||
|
||||
/**
|
||||
Export plugin dependencies as an array
|
||||
|
||||
@param {List<PluginDependency>} list
|
||||
@return {Array<String>}
|
||||
*/
|
||||
* Export plugin dependencies as an array
|
||||
* @param {List<PluginDependency>} list
|
||||
* @return {Array<String>}
|
||||
*/
|
||||
PluginDependency.listToArray = function(list) {
|
||||
return list
|
||||
.map(function(dep) {
|
||||
@@ -151,11 +157,10 @@ PluginDependency.listToArray = function(list) {
|
||||
};
|
||||
|
||||
/**
|
||||
Return NPM id for a plugin name
|
||||
|
||||
@param {String}
|
||||
@return {String}
|
||||
*/
|
||||
* Return NPM id for a plugin name
|
||||
* @param {String}
|
||||
* @return {String}
|
||||
*/
|
||||
PluginDependency.nameToNpmID = function(s) {
|
||||
return PREFIX + s;
|
||||
};
|
||||
|
||||
+32
-39
@@ -43,10 +43,9 @@ TemplateBlock.prototype.getBlocks = function() {
|
||||
|
||||
|
||||
/**
|
||||
Return shortcuts associated with this block or undefined
|
||||
|
||||
@return {TemplateShortcut|undefined}
|
||||
*/
|
||||
* Return shortcuts associated with this block or undefined
|
||||
* @return {TemplateShortcut|undefined}
|
||||
*/
|
||||
TemplateBlock.prototype.getShortcuts = function() {
|
||||
var shortcuts = this.get('shortcuts');
|
||||
if (shortcuts.size === 0) {
|
||||
@@ -57,19 +56,17 @@ TemplateBlock.prototype.getShortcuts = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
Return name for the nunjucks extension
|
||||
|
||||
@return {String}
|
||||
*/
|
||||
* Return name for the nunjucks extension
|
||||
* @return {String}
|
||||
*/
|
||||
TemplateBlock.prototype.getExtensionName = function() {
|
||||
return 'Block' + this.getName() + 'Extension';
|
||||
};
|
||||
|
||||
/**
|
||||
Return a nunjucks extension to represents this block
|
||||
|
||||
@return {Nunjucks.Extension}
|
||||
*/
|
||||
* Return a nunjucks extension to represents this block
|
||||
* @return {Nunjucks.Extension}
|
||||
*/
|
||||
TemplateBlock.prototype.toNunjucksExt = function(mainContext, blocksOutput) {
|
||||
blocksOutput = blocksOutput || {};
|
||||
|
||||
@@ -192,11 +189,11 @@ TemplateBlock.prototype.toNunjucksExt = function(mainContext, blocksOutput) {
|
||||
};
|
||||
|
||||
/**
|
||||
Apply a block to a content
|
||||
@param {Object} inner
|
||||
@param {Object} context
|
||||
@return {Promise<String>|String}
|
||||
*/
|
||||
* Apply a block to a content
|
||||
* @param {Object} inner
|
||||
* @param {Object} context
|
||||
* @return {Promise<String>|String}
|
||||
*/
|
||||
TemplateBlock.prototype.applyBlock = function(inner, context) {
|
||||
var processFn = this.getProcess();
|
||||
|
||||
@@ -215,11 +212,10 @@ TemplateBlock.prototype.applyBlock = function(inner, context) {
|
||||
};
|
||||
|
||||
/**
|
||||
Normalize result from a block process function
|
||||
|
||||
@param {Object|String} result
|
||||
@return {Object}
|
||||
*/
|
||||
* Normalize result from a block process function
|
||||
* @param {Object|String} result
|
||||
* @return {Object}
|
||||
*/
|
||||
TemplateBlock.prototype.normalizeBlockResult = function(result) {
|
||||
if (is.string(result)) {
|
||||
result = { body: result };
|
||||
@@ -230,12 +226,11 @@ TemplateBlock.prototype.normalizeBlockResult = function(result) {
|
||||
};
|
||||
|
||||
/**
|
||||
Convert a block result to HTML
|
||||
|
||||
@param {Object} result
|
||||
@param {Object} blocksOutput: stored post processing blocks in this object
|
||||
@return {String}
|
||||
*/
|
||||
* Convert a block result to HTML
|
||||
* @param {Object} result
|
||||
* @param {Object} blocksOutput: stored post processing blocks in this object
|
||||
* @return {String}
|
||||
*/
|
||||
TemplateBlock.prototype.blockResultToHtml = function(result, blocksOutput) {
|
||||
var indexedKey;
|
||||
var toIndex = (!result.parse) || (result.post !== undefined);
|
||||
@@ -256,12 +251,11 @@ TemplateBlock.prototype.blockResultToHtml = function(result, blocksOutput) {
|
||||
};
|
||||
|
||||
/**
|
||||
Create a template block from a function or an object
|
||||
|
||||
@param {String} blockName
|
||||
@param {Object} block
|
||||
@return {TemplateBlock}
|
||||
*/
|
||||
* Create a template block from a function or an object
|
||||
* @param {String} blockName
|
||||
* @param {Object} block
|
||||
* @return {TemplateBlock}
|
||||
*/
|
||||
TemplateBlock.create = function(blockName, block) {
|
||||
if (is.fn(block)) {
|
||||
block = new Immutable.Map({
|
||||
@@ -275,11 +269,10 @@ TemplateBlock.create = function(blockName, block) {
|
||||
};
|
||||
|
||||
/**
|
||||
Extract kwargs from an arguments array
|
||||
|
||||
@param {Array} args
|
||||
@return {Object}
|
||||
*/
|
||||
* Extract kwargs from an arguments array
|
||||
* @param {Array} args
|
||||
* @return {Object}
|
||||
*/
|
||||
function extractKwargs(args) {
|
||||
var last = args[args.length - 1];
|
||||
return (is.object(last) && last.__keywords)? args.pop() : {};
|
||||
|
||||
@@ -17,23 +17,21 @@ TemplateOutput.prototype.getBlocks = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
Update content of this output
|
||||
|
||||
@param {String} content
|
||||
@return {TemplateContent}
|
||||
*/
|
||||
* Update content of this output
|
||||
* @param {String} content
|
||||
* @return {TemplateContent}
|
||||
*/
|
||||
TemplateOutput.prototype.setContent = function(content) {
|
||||
return this.set('content', content);
|
||||
};
|
||||
|
||||
/**
|
||||
Create a TemplateOutput from a text content
|
||||
and an object containing block definition
|
||||
|
||||
@param {String} content
|
||||
@param {Object} blocks
|
||||
@return {TemplateOutput}
|
||||
*/
|
||||
* Create a TemplateOutput from a text content
|
||||
* and an object containing block definition
|
||||
* @param {String} content
|
||||
* @param {Object} blocks
|
||||
* @return {TemplateOutput}
|
||||
*/
|
||||
TemplateOutput.create = function(content, blocks) {
|
||||
return new TemplateOutput({
|
||||
content: content,
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
var togglePlugin = require('../togglePlugin');
|
||||
var Config = require('../../../models/config');
|
||||
var Book = require('../../../models/book');
|
||||
|
||||
describe('togglePlugin', function() {
|
||||
var config = Config.createWithValues({
|
||||
plugins: ['hello', 'world', '-disabled']
|
||||
});
|
||||
var book = Book().setConfig(config);
|
||||
|
||||
it('should enable plugin', function() {
|
||||
var newBook = togglePlugin(book, 'disabled');
|
||||
var newConfig = newBook.getConfig();
|
||||
|
||||
var testDep = newConfig.getPluginDependency('disabled');
|
||||
expect(testDep).toBeDefined();
|
||||
expect(testDep.getVersion()).toEqual('*');
|
||||
expect(testDep.isEnabled()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should disable plugin', function() {
|
||||
var newBook = togglePlugin(book, 'world');
|
||||
var newConfig = newBook.getConfig();
|
||||
|
||||
var testDep = newConfig.getPluginDependency('world');
|
||||
expect(testDep).toBeDefined();
|
||||
expect(testDep.getVersion()).toEqual('*');
|
||||
expect(testDep.isEnabled()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
var PluginDependency = require('../../models/pluginDependency');
|
||||
/**
|
||||
Add a plugin to a book's configuration
|
||||
|
||||
@param {Book} book
|
||||
@param {String} plugin
|
||||
@param {String} version (optional)
|
||||
@return {Book}
|
||||
*/
|
||||
/**
|
||||
* Add a plugin to a book's configuration
|
||||
* @param {Book} book
|
||||
* @param {String} plugin
|
||||
* @param {String} version (optional)
|
||||
* @return {Book}
|
||||
*/
|
||||
function addPlugin(book, plugin, version) {
|
||||
var config = book.getConfig();
|
||||
var deps = config.getPluginDependencies();
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
/**
|
||||
* Edit ocnfiguration of a plugin
|
||||
* @param {Book} book
|
||||
* @param {String} plugin
|
||||
* @param {Object} pluginConfig
|
||||
* @return {Book}
|
||||
*/
|
||||
function editPlugin(book, pluginName, pluginConfig) {
|
||||
var config = book.getConfig();
|
||||
config = config.set('pluginsConfig.'+pluginName, pluginConfig);
|
||||
|
||||
return book.setConfig(config);
|
||||
}
|
||||
|
||||
module.exports = editPlugin;
|
||||
@@ -1,5 +1,7 @@
|
||||
|
||||
module.exports = {
|
||||
addPlugin: require('./addPlugin'),
|
||||
removePlugin: require('./removePlugin')
|
||||
addPlugin: require('./addPlugin'),
|
||||
removePlugin: require('./removePlugin'),
|
||||
togglePlugin: require('./togglePlugin'),
|
||||
editPlugin: require('./editPlugin')
|
||||
};
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
|
||||
/**
|
||||
Remove a plugin from a book's configuration
|
||||
|
||||
@param {Book} book
|
||||
@param {String} plugin
|
||||
@return {Book}
|
||||
*/
|
||||
* Remove a plugin from a book's configuration
|
||||
* @param {Book} book
|
||||
* @param {String} plugin
|
||||
* @return {Book}
|
||||
*/
|
||||
function removePlugin(book, pluginName) {
|
||||
var config = book.getConfig();
|
||||
var deps = config.getPluginDependencies();
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
/**
|
||||
* Enable/disable a plugin dependency
|
||||
* @param {Book} book
|
||||
* @param {String} plugin
|
||||
* @param {Boolean} state (optional)
|
||||
* @return {Book}
|
||||
*/
|
||||
function togglePlugin(book, plugin, state) {
|
||||
var config = book.getConfig();
|
||||
var deps = config.getPluginDependencies();
|
||||
|
||||
deps = deps.map(function(dep) {
|
||||
if (dep.getName() === plugin) {
|
||||
return dep.toggle(state);
|
||||
}
|
||||
|
||||
return dep;
|
||||
});
|
||||
|
||||
config = config.setPluginDependencies(deps);
|
||||
return book.setConfig(config);
|
||||
}
|
||||
|
||||
module.exports = togglePlugin;
|
||||
@@ -19,7 +19,13 @@ var generateBook = require('./generateBook');
|
||||
function generateMock(Generator, files) {
|
||||
var fs = createMockFS(files);
|
||||
var book = Book.createForFS(fs);
|
||||
var dir = tmp.dirSync();
|
||||
var dir;
|
||||
|
||||
try {
|
||||
dir = tmp.dirSync();
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
book = book.setLogLevel('disabled');
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
var parseStructureFile = require('./parseStructureFile');
|
||||
var Summary = require('../models/summary');
|
||||
var SummaryModifier = require('../modifiers').Summary;
|
||||
var location = require('../utils/location');
|
||||
|
||||
/**
|
||||
Parse summary in a book, the summary can only be parsed
|
||||
@@ -27,11 +26,10 @@ function parseSummary(book) {
|
||||
summary = Summary.createFromParts(file, result.parts);
|
||||
}
|
||||
|
||||
// Insert readme as first entry
|
||||
var firstArticle = summary.getFirstArticle();
|
||||
// Insert readme as first entry if not in SUMMARY.md
|
||||
var readmeArticle = summary.getByPath(readmeFile.getPath());
|
||||
|
||||
if (readmeFile.exists() &&
|
||||
(!firstArticle || !location.areIdenticalPaths(firstArticle.getRef(), readmeFile.getPath()))) {
|
||||
if (readmeFile.exists() && !readmeArticle) {
|
||||
summary = SummaryModifier.unshiftArticle(summary, {
|
||||
title: 'Introduction',
|
||||
ref: readmeFile.getPath()
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
var PluginDependency = require('../../models/pluginDependency');
|
||||
var sortPlugins = require('../sortPlugins');
|
||||
var listAll = require('../listAll');
|
||||
var THEME_PREFIX = require('../../constants/themePrefix');
|
||||
|
||||
|
||||
/**
|
||||
Check if a plugin is a theme given its name
|
||||
|
||||
@return {Boolean}
|
||||
*/
|
||||
function isTheme(name) {
|
||||
return (name && name.indexOf(THEME_PREFIX) === 0);
|
||||
}
|
||||
|
||||
describe('sortPlugins', function() {
|
||||
it('must load themes after plugins', function() {
|
||||
var deps = PluginDependency.listFromString('theme-faq'),
|
||||
allPlugins = listAll(deps);
|
||||
|
||||
return sortPlugins(allPlugins, [])
|
||||
.then(function(sorted) {
|
||||
var plugins = sorted.slice(0, -2),
|
||||
themes = sorted.slice(-2);
|
||||
|
||||
var pluginsOk = plugins.every(function(plugin) {
|
||||
return !isTheme(plugin.getName());
|
||||
});
|
||||
|
||||
var themesOk = themes.every(function(theme) {
|
||||
return isTheme(theme.getName());
|
||||
});
|
||||
|
||||
expect(pluginsOk).toBe(true);
|
||||
expect(plugins.has('search')).toBe(true);
|
||||
|
||||
expect(themesOk).toBe(true);
|
||||
expect(themes.size).toBe(2);
|
||||
expect(themes.has('theme-faq')).toBe(true);
|
||||
expect(themes.has('theme-default')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('must load themes after plugins with a complex dependencies list', function() {
|
||||
var deps = PluginDependency.listFromString('comment,theme-faq,-search,ga'),
|
||||
allPlugins = listAll(deps);
|
||||
|
||||
return sortPlugins(allPlugins, [])
|
||||
.then(function(sorted) {
|
||||
var plugins = sorted.slice(0, -2),
|
||||
themes = sorted.slice(-2);
|
||||
|
||||
var pluginsOk = plugins.every(function(plugin) {
|
||||
return !isTheme(plugin.getName());
|
||||
});
|
||||
|
||||
var themesOk = themes.every(function(theme) {
|
||||
return isTheme(theme.getName());
|
||||
});
|
||||
|
||||
expect(pluginsOk).toBe(true);
|
||||
expect(plugins.has('search')).toBe(false);
|
||||
|
||||
expect(themesOk).toBe(true);
|
||||
expect(themes.size).toBe(2);
|
||||
expect(themes.has('theme-faq')).toBe(true);
|
||||
expect(themes.has('theme-default')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -3,6 +3,7 @@ var Promise = require('../utils/promise');
|
||||
var listForBook = require('./listForBook');
|
||||
var findForBook = require('./findForBook');
|
||||
var loadPlugin = require('./loadPlugin');
|
||||
var sortPlugins = require('./sortPlugins');
|
||||
|
||||
|
||||
/**
|
||||
@@ -27,11 +28,9 @@ function loadForBook(book) {
|
||||
);
|
||||
});
|
||||
|
||||
// Sort plugins to match list in book.json
|
||||
installed = installed.sort(function(a, b){
|
||||
return requirementsKeys.indexOf(a.getName()) < requirementsKeys.indexOf(b.getName()) ? -1 : 1;
|
||||
});
|
||||
|
||||
return sortPlugins(installed, requirementsKeys);
|
||||
})
|
||||
.then(function(installed) {
|
||||
// Log state
|
||||
logger.info.ln(installed.size + ' plugins are installed');
|
||||
if (requirements.size != installed.size) {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
var Promise = require('../utils/promise');
|
||||
|
||||
var THEME_PREFIX = require('../constants/themePrefix');
|
||||
var LOADING_ORDER = ['plugin', 'theme'];
|
||||
|
||||
/**
|
||||
Returns the type of a plugin given its name
|
||||
|
||||
@return {String}
|
||||
*/
|
||||
function pluginType(name) {
|
||||
return (name && name.indexOf(THEME_PREFIX) === 0) ? 'theme' : 'plugin';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Sort the list of installed plugins to match list in book.json
|
||||
The themes should always be loaded after the plugins
|
||||
|
||||
@param {<OrderedMap<String:Plugin>>} plugins
|
||||
@param {<List<String>>} requirementsKeys
|
||||
@return {Promise<OrderedMap<String:Plugin>>}
|
||||
*/
|
||||
|
||||
function sortPlugins(plugins, requirementsKeys) {
|
||||
return Promise()
|
||||
.then(function() {
|
||||
// Sort plugins to match list in book.json
|
||||
plugins = plugins.sort(function(a, b) {
|
||||
// Get order from book.json
|
||||
var definitionOrder = requirementsKeys.indexOf(a.getName()) < requirementsKeys.indexOf(b.getName());
|
||||
|
||||
// Get order from plugins a and b type
|
||||
var aType = pluginType(a.getName()),
|
||||
bType = pluginType(b.getName()),
|
||||
loadingOrder = LOADING_ORDER.indexOf(aType) < LOADING_ORDER.indexOf(bType);
|
||||
|
||||
return loadingOrder || definitionOrder ? -1 : 1;
|
||||
});
|
||||
|
||||
return plugins;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = sortPlugins;
|
||||
@@ -0,0 +1,51 @@
|
||||
var TemplateEngine = require('../../models/templateEngine');
|
||||
var TemplateBlock = require('../../models/templateBlock');
|
||||
|
||||
var renderTemplate = require('../render');
|
||||
var postRender = require('../postRender');
|
||||
|
||||
describe('postRender', function() {
|
||||
var testPost;
|
||||
var engine = TemplateEngine.create({
|
||||
blocks: [
|
||||
TemplateBlock.create('lower', function(blk) {
|
||||
return blk.body.toLowerCase();
|
||||
}),
|
||||
TemplateBlock.create('prefix', function(blk) {
|
||||
return {
|
||||
body: '_' + blk.body + '_',
|
||||
post: function() {
|
||||
testPost = true;
|
||||
}
|
||||
};
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
it('should correctly replace block', function() {
|
||||
return renderTemplate(engine, 'README.md', 'Hello {% lower %}Samy{% endlower %}')
|
||||
.then(function(output) {
|
||||
expect(output.getContent()).toMatch(/Hello \{\{\-([\S]+)\-\}\}/);
|
||||
expect(output.getBlocks().size).toBe(1);
|
||||
|
||||
return postRender(engine, output);
|
||||
})
|
||||
.then(function(result) {
|
||||
expect(result).toBe('Hello samy');
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly replace blocks', function() {
|
||||
return renderTemplate(engine, 'README.md', 'Hello {% lower %}Samy{% endlower %}{% prefix %}Pesse{% endprefix %}')
|
||||
.then(function(output) {
|
||||
expect(output.getContent()).toMatch(/Hello \{\{\-([\S]+)\-\}\}\{\{\-([\S]+)\-\}\}/);
|
||||
expect(output.getBlocks().size).toBe(2);
|
||||
return postRender(engine, output);
|
||||
})
|
||||
.then(function(result) {
|
||||
expect(result).toBe('Hello samy_Pesse_');
|
||||
expect(testPost).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -2,12 +2,12 @@ var Promise = require('../utils/promise');
|
||||
|
||||
|
||||
/**
|
||||
Replace position markers of blocks by body after processing
|
||||
This is done to avoid that markdown/asciidoc processer parse the block content
|
||||
|
||||
@param {String} content
|
||||
@return {Object} {blocks: Set, content: String}
|
||||
*/
|
||||
* Replace position markers of blocks by body after processing
|
||||
* This is done to avoid that markdown/asciidoc processer parse the block content
|
||||
*
|
||||
* @param {String} content
|
||||
* @return {Object} {blocks: Set, content: String}
|
||||
*/
|
||||
function replaceBlocks(content, blocks) {
|
||||
var newContent = content.replace(/\{\{\-\%([\s\S]+?)\%\-\}\}/g, function(match, key) {
|
||||
var replacedWith = match;
|
||||
@@ -24,14 +24,14 @@ function replaceBlocks(content, blocks) {
|
||||
}
|
||||
|
||||
/**
|
||||
Post render a template:
|
||||
- Execute "post" for blocks
|
||||
- Replace block content
|
||||
|
||||
@param {TemplateEngine} engine
|
||||
@param {TemplateOutput} content
|
||||
@return {Promise<String>}
|
||||
*/
|
||||
* Post render a template:
|
||||
* - Execute "post" for blocks
|
||||
* - Replace block content
|
||||
*
|
||||
* @param {TemplateEngine} engine
|
||||
* @param {TemplateOutput} content
|
||||
* @return {Promise<String>}
|
||||
*/
|
||||
function postRender(engine, output) {
|
||||
var content = output.getContent();
|
||||
var blocks = output.getBlocks();
|
||||
|
||||
@@ -4,14 +4,14 @@ var TemplateOutput = require('../models/templateOutput');
|
||||
var replaceShortcuts = require('./replaceShortcuts');
|
||||
|
||||
/**
|
||||
Render a template
|
||||
|
||||
@param {TemplateEngine} engine
|
||||
@param {String} filePath: absolute path for the loader
|
||||
@param {String} content
|
||||
@param {Object} context
|
||||
@return {Promise<TemplateOutput>}
|
||||
*/
|
||||
* Render a template
|
||||
*
|
||||
* @param {TemplateEngine} engine
|
||||
* @param {String} filePath: absolute path for the loader
|
||||
* @param {String} content
|
||||
* @param {Object} context (optional)
|
||||
* @return {Promise<TemplateOutput>}
|
||||
*/
|
||||
function renderTemplate(engine, filePath, content, context) {
|
||||
context = context || {};
|
||||
|
||||
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gitbook",
|
||||
"version": "3.0.3",
|
||||
"version": "3.1.0",
|
||||
"homepage": "https://www.gitbook.com",
|
||||
"description": "Library and cmd utility to generate GitBooks",
|
||||
"main": "lib/index.js",
|
||||
@@ -21,15 +21,15 @@
|
||||
"extend": "^3.0.0",
|
||||
"fresh-require": "1.0.3",
|
||||
"front-matter": "2.0.8",
|
||||
"gitbook-asciidoc": "1.1.4",
|
||||
"gitbook-markdown": "1.2.3",
|
||||
"gitbook-plugin-fontsettings": "1.0.3",
|
||||
"gitbook-asciidoc": "1.2.0",
|
||||
"gitbook-markdown": "1.3.0",
|
||||
"gitbook-plugin-fontsettings": "2.0.0",
|
||||
"gitbook-plugin-highlight": "2.0.2",
|
||||
"gitbook-plugin-livereload": "0.0.1",
|
||||
"gitbook-plugin-lunr": "1.1.0",
|
||||
"gitbook-plugin-search": "2.2.1",
|
||||
"gitbook-plugin-sharing": "1.0.2",
|
||||
"gitbook-plugin-theme-default": "1.0.3",
|
||||
"gitbook-plugin-theme-default": "1.0.4",
|
||||
"github-slugid": "1.0.1",
|
||||
"graceful-fs": "4.1.4",
|
||||
"i18n-t": "1.0.0",
|
||||
|
||||
Reference in New Issue
Block a user