mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-28 04:58:52 +00:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 42a2d090aa | |||
| c84eaa83dd | |||
| 74c3ff80cb | |||
| 5893d3ee64 | |||
| 7f435c56a0 | |||
| 59b7100cf6 | |||
| 0923d1aa24 | |||
| ffe6c36f2f | |||
| 8c4752c5d8 | |||
| d6202e522b | |||
| 50a24c62c5 | |||
| 6b17d08892 | |||
| 79c91fd8c5 | |||
| 95764258ab | |||
| 41e6872557 | |||
| 30c96c37c2 | |||
| 20f1cf3dff | |||
| 8de0d6186e | |||
| edd7d8aefe | |||
| a8da4903f4 | |||
| c8df5033f7 | |||
| 412f418da3 | |||
| 3782d21069 | |||
| 82a29f4470 | |||
| 4a65326b24 | |||
| d75d8729be | |||
| c87060454e | |||
| bbba52c7ff | |||
| 33418bdb33 | |||
| de47db2b66 | |||
| fa6fcffbe1 | |||
| 93d3f11891 | |||
| 59479f10fc |
@@ -17,6 +17,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- Fix `uk` translation
|
||||
- Fix heading ID including dashes
|
||||
- Fix error in code highlighting for unknown languages
|
||||
- Fix data-uri images being handled as external images
|
||||
- Accept SSH url as plugin version
|
||||
- Add templating blocks `markdown`, `asciidoc` and `markup`
|
||||
- Better search experience
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ function createMockFS(files) {
|
||||
var mtime = new Date();
|
||||
|
||||
function getFile(filePath) {
|
||||
var parts = path.normalize(filePath).split('/');
|
||||
var parts = path.normalize(filePath).split(path.sep);
|
||||
return parts.reduce(function(list, part, i) {
|
||||
if (!list) return null;
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
jest.autoMockOff();
|
||||
|
||||
describe('Plugin', function() {
|
||||
var Plugin = require('../plugin');
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
describe('PluginDependency', function() {
|
||||
var PluginDependency = require('../pluginDependency');
|
||||
|
||||
describe('createFromString', function() {
|
||||
it('must parse name', function() {
|
||||
var plugin = PluginDependency.createFromString('hello');
|
||||
expect(plugin.getName()).toBe('hello');
|
||||
expect(plugin.getVersion()).toBe('*');
|
||||
});
|
||||
|
||||
it('must parse state', function() {
|
||||
var plugin = PluginDependency.createFromString('-hello');
|
||||
expect(plugin.getName()).toBe('hello');
|
||||
expect(plugin.isEnabled()).toBe(false);
|
||||
});
|
||||
|
||||
describe('Version', function() {
|
||||
it('must parse version', function() {
|
||||
var plugin = PluginDependency.createFromString('hello@1.0.0');
|
||||
expect(plugin.getName()).toBe('hello');
|
||||
expect(plugin.getVersion()).toBe('1.0.0');
|
||||
});
|
||||
|
||||
it('must parse semver', function() {
|
||||
var plugin = PluginDependency.createFromString('hello@>=4.0.0');
|
||||
expect(plugin.getName()).toBe('hello');
|
||||
expect(plugin.getVersion()).toBe('>=4.0.0');
|
||||
});
|
||||
});
|
||||
|
||||
describe('GIT Version', function() {
|
||||
it('must handle HTTPS urls', function() {
|
||||
var plugin = PluginDependency.createFromString('hello@git+https://github.com/GitbookIO/plugin-ga.git');
|
||||
expect(plugin.getName()).toBe('hello');
|
||||
expect(plugin.getVersion()).toBe('git+https://github.com/GitbookIO/plugin-ga.git');
|
||||
});
|
||||
|
||||
it('must handle SSH urls', function() {
|
||||
var plugin = PluginDependency.createFromString('hello@git+ssh://samy@github.com/GitbookIO/plugin-ga.git');
|
||||
expect(plugin.getName()).toBe('hello');
|
||||
expect(plugin.getVersion()).toBe('git+ssh://samy@github.com/GitbookIO/plugin-ga.git');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -244,6 +244,58 @@ Book.createForFS = function createForFS(fs) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
Infers the default extension for files
|
||||
@return {String}
|
||||
*/
|
||||
Book.prototype.getDefaultExt = function() {
|
||||
// Inferring sources
|
||||
var clues = [
|
||||
this.getReadme(),
|
||||
this.getSummary(),
|
||||
this.getGlossary()
|
||||
];
|
||||
|
||||
// List their extensions
|
||||
var exts = clues.map(function (clue) {
|
||||
var file = clue.getFile();
|
||||
if (file.exists()) {
|
||||
return file.getParser().getExtensions().first();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
// Adds the general default extension
|
||||
exts.push('.md');
|
||||
|
||||
// Choose the first non null
|
||||
return exts.find(function (e) { return e !== null; });
|
||||
};
|
||||
|
||||
/**
|
||||
Infer the default path for a Readme.
|
||||
@return {String}
|
||||
*/
|
||||
Book.prototype.getDefaultReadmePath = function() {
|
||||
return this.getContentRoot()+'README'+this.getDefaultExt();
|
||||
};
|
||||
|
||||
/**
|
||||
Infer the default path for a Summary.
|
||||
@return {String}
|
||||
*/
|
||||
Book.prototype.getDefaultSummaryPath = function() {
|
||||
return this.getContentRoot()+'SUMMARY'+this.getDefaultExt();
|
||||
};
|
||||
|
||||
/**
|
||||
Infer the default path for a Glossary.
|
||||
@return {String}
|
||||
*/
|
||||
Book.prototype.getDefaultGlossaryPath = function() {
|
||||
return this.getContentRoot()+'GLOSSARY'+this.getDefaultExt();
|
||||
};
|
||||
|
||||
/**
|
||||
Create a language book from a parent
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ var is = require('is');
|
||||
var Immutable = require('immutable');
|
||||
|
||||
var File = require('./file');
|
||||
var PluginDependency = require('./pluginDependency');
|
||||
var configDefault = require('../constants/configDefault');
|
||||
|
||||
var Config = Immutable.Record({
|
||||
@@ -52,6 +53,33 @@ Config.prototype.setValue = function(keyPath, value) {
|
||||
return this.set('values', values);
|
||||
};
|
||||
|
||||
/**
|
||||
Return a list of plugin dependencies
|
||||
|
||||
@return {List<PluginDependency>}
|
||||
*/
|
||||
Config.prototype.getPluginDependencies = function() {
|
||||
var plugins = this.getValue('plugins');
|
||||
|
||||
if (is.string(plugins)) {
|
||||
return PluginDependency.listFromString(plugins);
|
||||
} else {
|
||||
return PluginDependency.listFromArray(plugins);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Update the list of plugins dependencies
|
||||
|
||||
@param {List<PluginDependency>}
|
||||
@return {Config}
|
||||
*/
|
||||
Config.prototype.setPluginDependencies = function(deps) {
|
||||
var plugins = PluginDependency.listFromArray(deps);
|
||||
|
||||
return this.setValue('plugins', plugins);
|
||||
};
|
||||
|
||||
/**
|
||||
Create a new config for a file
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ Languages.createFromList = function(file, langs) {
|
||||
langs.forEach(function(lang) {
|
||||
lang = Language({
|
||||
title: lang.title,
|
||||
path: lang.path
|
||||
path: lang.ref
|
||||
});
|
||||
list = list.set(lang.getID(), lang);
|
||||
});
|
||||
|
||||
@@ -139,6 +139,19 @@ Plugin.createFromString = function(s) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
Create a plugin from a dependency
|
||||
|
||||
@param {PluginDependency}
|
||||
@return {Plugin}
|
||||
*/
|
||||
Plugin.createFromDep = function(dep) {
|
||||
return new Plugin({
|
||||
name: dep.getName(),
|
||||
version: dep.getVersion()
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
Return NPM id for a plugin name
|
||||
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
var is = require('is');
|
||||
var Immutable = require('immutable');
|
||||
|
||||
var DEFAULT_VERSION = '*';
|
||||
|
||||
/*
|
||||
PluginDependency represents the informations about a plugin
|
||||
stored in config.plugins
|
||||
*/
|
||||
var PluginDependency = Immutable.Record({
|
||||
name: String(),
|
||||
|
||||
// Requirement version (ex: ">1.0.0")
|
||||
version: String(DEFAULT_VERSION),
|
||||
|
||||
// Is this plugin enabled or disabled?
|
||||
enabled: Boolean(true)
|
||||
}, 'PluginDependency');
|
||||
|
||||
PluginDependency.prototype.getName = function() {
|
||||
return this.get('name');
|
||||
};
|
||||
|
||||
PluginDependency.prototype.getVersion = function() {
|
||||
return this.get('version');
|
||||
};
|
||||
|
||||
PluginDependency.prototype.isEnabled = function() {
|
||||
return this.get('enabled');
|
||||
};
|
||||
|
||||
/**
|
||||
Create a plugin from a string
|
||||
|
||||
@param {String}
|
||||
@return {Plugin|undefined}
|
||||
*/
|
||||
PluginDependency.createFromString = function(s) {
|
||||
var parts = s.split('@');
|
||||
var name = parts[0];
|
||||
var version = parts.slice(1).join('@');
|
||||
var enabled = true;
|
||||
|
||||
if (name[0] === '-') {
|
||||
enabled = false;
|
||||
name = name.slice(1);
|
||||
}
|
||||
|
||||
return new PluginDependency({
|
||||
name: name,
|
||||
version: version || DEFAULT_VERSION,
|
||||
enabled: enabled
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
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>}
|
||||
*/
|
||||
PluginDependency.listFromArray = function(arr) {
|
||||
return Immutable.List(arr)
|
||||
.map(function(entry) {
|
||||
if (is.string(entry)) {
|
||||
return PluginDependency.createFromString(entry);
|
||||
} else {
|
||||
return PluginDependency({
|
||||
name: entry.name,
|
||||
version: entry.version
|
||||
});
|
||||
}
|
||||
})
|
||||
.filter(function(dep) {
|
||||
return Boolean(dep.getName());
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
Export plugin dependencies as an array
|
||||
|
||||
@param {List<PluginDependency>}
|
||||
@return {Array<String>}
|
||||
*/
|
||||
PluginDependency.listToArray = function(arr) {
|
||||
return arr
|
||||
.map(function(dep) {
|
||||
var result;
|
||||
|
||||
if (dep.isEnabled()) {
|
||||
result += '-';
|
||||
}
|
||||
|
||||
result += dep.getName();
|
||||
if (dep.getVersion() !== DEFAULT_VERSION) {
|
||||
result += '@' + dep.getVersion();
|
||||
}
|
||||
|
||||
return result;
|
||||
})
|
||||
.toJS();
|
||||
};
|
||||
|
||||
module.exports = PluginDependency;
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
var PluginDependency = require('../../models/pluginDependency');
|
||||
/**
|
||||
Add a plugin to a book's configuration
|
||||
|
||||
@@ -9,10 +9,15 @@
|
||||
*/
|
||||
function addPlugin(book, plugin, version) {
|
||||
var config = book.getConfig();
|
||||
var plugins = config.getValue('plugins', []);
|
||||
var deps = config.getPluginDependencies();
|
||||
|
||||
plugins = plugins.push('livereload');
|
||||
config = config.setValue('plugins', plugins);
|
||||
var dep = PluginDependency({
|
||||
name: plugin,
|
||||
version: version
|
||||
});
|
||||
|
||||
deps = deps.push(dep);
|
||||
config = config.setPluginDependencies(deps);
|
||||
|
||||
return book.setConfig(config);
|
||||
}
|
||||
|
||||
@@ -8,15 +8,13 @@
|
||||
*/
|
||||
function removePlugin(book, pluginName) {
|
||||
var config = book.getConfig();
|
||||
var plugins = config.getValue('plugins', []);
|
||||
var deps = config.getPluginDependencies();
|
||||
|
||||
// Find index of this plugin
|
||||
var index = plugins.findIndex(function(plugin) {
|
||||
return plugin === pluginName;
|
||||
|
||||
deps = deps.filter(function(dep) {
|
||||
return dep.getName() === pluginName;
|
||||
});
|
||||
|
||||
plugins = plugins.delete(index);
|
||||
config = config.setValue('plugins', plugins);
|
||||
config = config.setPluginDependencies(deps);
|
||||
|
||||
return book.setConfig(config);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ var command = require('../../utils/command');
|
||||
var writeFile = require('../helper/writeFile');
|
||||
|
||||
var getConvertOptions = require('./getConvertOptions');
|
||||
var SUMMARY_FILE = 'SUMMARY.html';
|
||||
|
||||
/**
|
||||
Write the SUMMARY.html
|
||||
@@ -20,12 +21,12 @@ function writeSummary(output) {
|
||||
var options = output.getOptions();
|
||||
var prefix = options.get('prefix');
|
||||
|
||||
var filePath = 'SUMMARY.html';
|
||||
var filePath = SUMMARY_FILE;
|
||||
var engine = WebsiteGenerator.createTemplateEngine(output, filePath);
|
||||
var context = JSONUtils.encodeOutput(output);
|
||||
|
||||
// Render the theme
|
||||
return Templating.renderFile(engine, prefix + '/SUMMARY.html', context)
|
||||
return Templating.renderFile(engine, prefix + '/summary.html', context)
|
||||
|
||||
// Write it to the disk
|
||||
.then(function(html) {
|
||||
@@ -53,7 +54,7 @@ function runEbookConvert(output) {
|
||||
.then(function(options) {
|
||||
var cmd = [
|
||||
'ebook-convert',
|
||||
path.resolve(outputFolder, 'SUMMARY.html'),
|
||||
path.resolve(outputFolder, SUMMARY_FILE),
|
||||
path.resolve(outputFolder, 'index.' + format),
|
||||
command.optionsToShellArgs(options)
|
||||
].join(' ');
|
||||
|
||||
@@ -12,7 +12,7 @@ function onPage(output, page) {
|
||||
|
||||
// Inline assets
|
||||
return Modifiers.modifyHTML(page, [
|
||||
Modifiers.inlineAssets(options.get('root'))
|
||||
Modifiers.inlineAssets(options.get('root'), page.getFile().getPath())
|
||||
])
|
||||
|
||||
// Write page using website generator
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
var cheerio = require('cheerio');
|
||||
var tmp = require('tmp');
|
||||
var inlinePng = require('../inlinePng');
|
||||
|
||||
describe('inlinePng', function() {
|
||||
var dir;
|
||||
|
||||
beforeEach(function() {
|
||||
dir = tmp.dirSync();
|
||||
});
|
||||
|
||||
pit('should write an inline PNG using data URI as a file', function() {
|
||||
var $ = cheerio.load('<img alt="GitBook Logo 20x20" src="data:image/png;base64,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"/>');
|
||||
|
||||
return inlinePng(dir.name, 'index.html', $)
|
||||
.then(function() {
|
||||
var $img = $('img');
|
||||
var src = $img.attr('src');
|
||||
|
||||
expect(dir.name).toHaveFile(src);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
var is = require('is');
|
||||
var Immutable = require('immutable');
|
||||
|
||||
var Promise = require('../../utils/promise');
|
||||
var editHTMLElement = require('./editHTMLElement');
|
||||
|
||||
@@ -9,7 +11,7 @@ var editHTMLElement = require('./editHTMLElement');
|
||||
@return {String}
|
||||
*/
|
||||
function getLanguageForClass(classNames) {
|
||||
return classNames
|
||||
return Immutable.List(classNames)
|
||||
.map(function(cl) {
|
||||
// Markdown
|
||||
if (cl.search('lang-') === 0) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
var svgToImg = require('./svgToImg');
|
||||
var svgToPng = require('./svgToPng');
|
||||
var inlinePng = require('./inlinePng');
|
||||
var resolveImages = require('./resolveImages');
|
||||
var fetchRemoteImages = require('./fetchRemoteImages');
|
||||
|
||||
@@ -20,7 +21,8 @@ function inlineAssets(rootFolder, currentFile) {
|
||||
.then(fetchRemoteImages.bind(null, rootFolder, currentFile, $))
|
||||
|
||||
.then(svgToImg.bind(null, rootFolder, currentFile, $))
|
||||
.then(svgToPng.bind(null, rootFolder, currentFile, $));
|
||||
.then(svgToPng.bind(null, rootFolder, currentFile, $))
|
||||
.then(inlinePng.bind(null, rootFolder, currentFile, $));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
var crc = require('crc');
|
||||
var path = require('path');
|
||||
|
||||
var imagesUtil = require('../../utils/images');
|
||||
var fs = require('../../utils/fs');
|
||||
var LocationUtils = require('../../utils/location');
|
||||
|
||||
var editHTMLElement = require('./editHTMLElement');
|
||||
|
||||
/**
|
||||
Convert all inline PNG images to PNG file
|
||||
|
||||
@param {String} rootFolder
|
||||
@param {HTMLDom} $
|
||||
@return {Promise}
|
||||
*/
|
||||
function inlinePng(rootFolder, currentFile, $) {
|
||||
var currentDirectory = path.dirname(currentFile);
|
||||
|
||||
return editHTMLElement($, 'img', function($img) {
|
||||
var src = $img.attr('src');
|
||||
if (!LocationUtils.isDataURI(src)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We avoid generating twice the same PNG
|
||||
var hash = crc.crc32(src).toString(16);
|
||||
var fileName = hash + '.png';
|
||||
|
||||
// Result file path
|
||||
var filePath = path.join(rootFolder, fileName);
|
||||
|
||||
return fs.assertFile(filePath, function() {
|
||||
return imagesUtil.convertInlinePNG(src, filePath);
|
||||
})
|
||||
.then(function() {
|
||||
// Convert filename to a relative filename
|
||||
fileName = LocationUtils.relative(currentDirectory, fileName);
|
||||
|
||||
// Replace src
|
||||
$img.attr('src', fileName);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
module.exports = inlinePng;
|
||||
@@ -16,7 +16,7 @@ function resolveImages(currentFile, $) {
|
||||
return editHTMLElement($, 'img', function($img) {
|
||||
var src = $img.attr('src');
|
||||
|
||||
if (LocationUtils.isExternal(src)) {
|
||||
if (LocationUtils.isExternal(src) || LocationUtils.isDataURI(src)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
var is = require('is');
|
||||
|
||||
var Promise = require('../utils/promise');
|
||||
var Config = require('../models/config');
|
||||
|
||||
@@ -45,10 +43,6 @@ function parseConfig(book) {
|
||||
|
||||
values = validateConfig(values);
|
||||
|
||||
if (is.string(values.plugins)) {
|
||||
values.plugins = values.plugins.split(',');
|
||||
}
|
||||
|
||||
var config = Config.create(file, values);
|
||||
return book.set('config', config);
|
||||
});
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
var path = require('path');
|
||||
var Immutable = require('immutable');
|
||||
|
||||
describe('findInstalled', function() {
|
||||
var findInstalled = require('../findInstalled');
|
||||
|
||||
pit('must list default plugins for gitbook directory', function() {
|
||||
// Read gitbook-plugins from package.json
|
||||
var pkg = require(path.resolve(__dirname, '../../../package.json'));
|
||||
var gitbookPlugins = Immutable.Seq(pkg.dependencies)
|
||||
.filter(function(v, k) {
|
||||
return k.indexOf('gitbook-plugin') === 0;
|
||||
})
|
||||
.cacheResult();
|
||||
|
||||
return findInstalled(path.resolve(__dirname, '../../../'))
|
||||
.then(function(plugins) {
|
||||
expect(plugins.size > 7).toBeTruthy();
|
||||
expect(plugins.size >= gitbookPlugins.size).toBeTruthy();
|
||||
|
||||
expect(plugins.has('fontsettings')).toBe(true);
|
||||
expect(plugins.has('search')).toBe(true);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
jest.autoMockOff();
|
||||
var PluginDependency = require('../../models/pluginDependency');
|
||||
var listAll = require('../listAll');
|
||||
|
||||
describe('listAll', function() {
|
||||
var listAll = require('../listAll');
|
||||
|
||||
it('must list from string', function() {
|
||||
var plugins = listAll('ga,great');
|
||||
it('must list default', function() {
|
||||
var deps = PluginDependency.listFromString('ga,great');
|
||||
var plugins = listAll(deps);
|
||||
|
||||
expect(plugins.size).toBe(8);
|
||||
|
||||
@@ -14,45 +14,9 @@ describe('listAll', function() {
|
||||
expect(plugins.has('search')).toBe(true);
|
||||
});
|
||||
|
||||
it('must list from array', function() {
|
||||
var plugins = listAll(['ga', 'great']);
|
||||
|
||||
expect(plugins.size).toBe(8);
|
||||
|
||||
expect(plugins.has('ga')).toBe(true);
|
||||
expect(plugins.has('great')).toBe(true);
|
||||
|
||||
expect(plugins.has('search')).toBe(true);
|
||||
});
|
||||
|
||||
it('must parse version (semver)', function() {
|
||||
var plugins = listAll(['ga@1.0.0', 'great@>=4.0.0']);
|
||||
|
||||
expect(plugins.has('ga')).toBe(true);
|
||||
expect(plugins.has('great')).toBe(true);
|
||||
|
||||
var ga = plugins.get('ga');
|
||||
expect(ga.getVersion()).toBe('1.0.0');
|
||||
|
||||
var great = plugins.get('great');
|
||||
expect(great.getVersion()).toBe('>=4.0.0');
|
||||
});
|
||||
|
||||
it('must parse version (git)', function() {
|
||||
var plugins = listAll(['ga@git+https://github.com/GitbookIO/plugin-ga.git', 'great@git+ssh://samy@github.com/GitbookIO/plugin-ga.git']);
|
||||
|
||||
expect(plugins.has('ga')).toBe(true);
|
||||
expect(plugins.has('great')).toBe(true);
|
||||
|
||||
var ga = plugins.get('ga');
|
||||
expect(ga.getVersion()).toBe('git+https://github.com/GitbookIO/plugin-ga.git');
|
||||
|
||||
var great = plugins.get('great');
|
||||
expect(great.getVersion()).toBe('git+ssh://samy@github.com/GitbookIO/plugin-ga.git');
|
||||
});
|
||||
|
||||
it('must list from array with -', function() {
|
||||
var plugins = listAll(['ga', '-great']);
|
||||
var deps = PluginDependency.listFromString('ga,-great');
|
||||
var plugins = listAll(deps);
|
||||
|
||||
expect(plugins.size).toBe(7);
|
||||
|
||||
@@ -61,7 +25,8 @@ describe('listAll', function() {
|
||||
});
|
||||
|
||||
it('must remove default plugins using -', function() {
|
||||
var plugins = listAll(['ga', '-search']);
|
||||
var deps = PluginDependency.listFromString('ga,-search');
|
||||
var plugins = listAll(deps);
|
||||
|
||||
expect(plugins.size).toBe(6);
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ function installPlugins(book) {
|
||||
return Promise();
|
||||
}
|
||||
|
||||
logger.info.ln('installing', plugins.size, 'plugins');
|
||||
logger.info.ln('installing', plugins.size, 'plugins using npm@' + npmi.NPM_VERSION);
|
||||
|
||||
return Promise.forEach(plugins, function(plugin) {
|
||||
return installPlugin(book, plugin);
|
||||
|
||||
+13
-30
@@ -1,4 +1,3 @@
|
||||
var is = require('is');
|
||||
var Immutable = require('immutable');
|
||||
var Plugin = require('../models/plugin');
|
||||
|
||||
@@ -8,43 +7,27 @@ var DEFAULT_PLUGINS = require('../constants/defaultPlugins');
|
||||
/**
|
||||
List all plugins for a book
|
||||
|
||||
@param {List<Plugin|String>}
|
||||
@param {List<PluginDependency>} deps
|
||||
@return {OrderedMap<Plugin>}
|
||||
*/
|
||||
function listAll(plugins) {
|
||||
if (is.string(plugins)) {
|
||||
plugins = Immutable.List(plugins.split(','));
|
||||
}
|
||||
|
||||
// Convert to an ordered map
|
||||
plugins = plugins.map(function(plugin) {
|
||||
if (is.string(plugin)) {
|
||||
plugin = Plugin.createFromString(plugin);
|
||||
} else {
|
||||
plugin = new Plugin(plugin);
|
||||
}
|
||||
|
||||
return [plugin.getName(), plugin];
|
||||
});
|
||||
plugins = Immutable.OrderedMap(plugins);
|
||||
|
||||
function listAll(deps) {
|
||||
// Extract list of plugins to disable (starting with -)
|
||||
var toRemove = plugins.toList()
|
||||
var toRemove = deps
|
||||
.filter(function(plugin) {
|
||||
return plugin.getName()[0] === '-';
|
||||
return !plugin.isEnabled();
|
||||
})
|
||||
.map(function(plugin) {
|
||||
return plugin.getName().slice(1);
|
||||
return plugin.getName();
|
||||
});
|
||||
|
||||
// Remove the '-'
|
||||
plugins = plugins.mapKeys(function(name) {
|
||||
if (name[0] === '-') {
|
||||
return name.slice(1);
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
});
|
||||
// Convert to an ordered map of Plugin
|
||||
var plugins = deps
|
||||
.map(function(dep) {
|
||||
var plugin = Plugin.createFromDep(dep);
|
||||
|
||||
return [dep.getName(), plugin];
|
||||
});
|
||||
plugins = Immutable.OrderedMap(plugins);
|
||||
|
||||
// Append default plugins
|
||||
DEFAULT_PLUGINS.forEach(function(pluginName) {
|
||||
|
||||
@@ -10,7 +10,7 @@ var listAll = require('./listAll');
|
||||
*/
|
||||
function listForBook(book) {
|
||||
var config = book.getConfig();
|
||||
var plugins = config.getValue('plugins');
|
||||
var plugins = config.getPluginDependencies();
|
||||
|
||||
return listAll(plugins);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,15 @@ describe('LocationUtils', function() {
|
||||
expect(LocationUtils.isExternal('test.md')).toBe(false);
|
||||
expect(LocationUtils.isExternal('folder/test.md')).toBe(false);
|
||||
expect(LocationUtils.isExternal('/folder/test.md')).toBe(false);
|
||||
expect(LocationUtils.isExternal('data:image/png')).toBe(false);
|
||||
});
|
||||
|
||||
it('should correctly test data:uri location', function() {
|
||||
expect(LocationUtils.isDataURI('data:image/png')).toBe(true);
|
||||
expect(LocationUtils.isDataURI('http://google.fr')).toBe(false);
|
||||
expect(LocationUtils.isDataURI('https://google.fr')).toBe(false);
|
||||
expect(LocationUtils.isDataURI('test.md')).toBe(false);
|
||||
expect(LocationUtils.isDataURI('data.md')).toBe(false);
|
||||
});
|
||||
|
||||
it('should correctly detect anchor location', function() {
|
||||
|
||||
+42
-10
@@ -1,8 +1,15 @@
|
||||
var is = require('is');
|
||||
var childProcess = require('child_process');
|
||||
var spawn = require('spawn-cmd').spawn;
|
||||
var Promise = require('./promise');
|
||||
|
||||
// Execute a command
|
||||
/**
|
||||
Execute a command
|
||||
|
||||
@param {String} command
|
||||
@param {Object} options
|
||||
@return {Promise}
|
||||
*/
|
||||
function exec(command, options) {
|
||||
var d = Promise.defer();
|
||||
|
||||
@@ -26,7 +33,14 @@ function exec(command, options) {
|
||||
return d.promise;
|
||||
}
|
||||
|
||||
// Spawn an executable
|
||||
/**
|
||||
Spawn an executable
|
||||
|
||||
@param {String} command
|
||||
@param {Array} args
|
||||
@param {Object} options
|
||||
@return {Promise}
|
||||
*/
|
||||
function spawnCmd(command, args, options) {
|
||||
var d = Promise.defer();
|
||||
var child = spawn(command, args, options);
|
||||
@@ -54,12 +68,29 @@ function spawnCmd(command, args, options) {
|
||||
return d.promise;
|
||||
}
|
||||
|
||||
// Transform an option object to a command line string
|
||||
function escapeShellArg(s) {
|
||||
s = s.replace(/"/g, '\\"');
|
||||
return '"' + s + '"';
|
||||
/**
|
||||
Transform an option object to a command line string
|
||||
|
||||
@param {String|number} value
|
||||
@param {String}
|
||||
*/
|
||||
function escapeShellArg(value) {
|
||||
if (is.number(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
value = String(value);
|
||||
value = value.replace(/"/g, '\\"');
|
||||
|
||||
return '"' + value + '"';
|
||||
}
|
||||
|
||||
/**
|
||||
Transform a map of options into a command line arguments string
|
||||
|
||||
@param {Object} options
|
||||
@return {String}
|
||||
*/
|
||||
function optionsToShellArgs(options) {
|
||||
var result = [];
|
||||
|
||||
@@ -69,11 +100,12 @@ function optionsToShellArgs(options) {
|
||||
if (value === null || value === undefined || value === false) {
|
||||
continue;
|
||||
}
|
||||
if (value === true) {
|
||||
result.push(key);
|
||||
}
|
||||
|
||||
result.push(key + '=' + escapeShellArg(value));
|
||||
if (is.bool(value)) {
|
||||
result.push(key);
|
||||
} else {
|
||||
result.push(key + '=' + escapeShellArg(value));
|
||||
}
|
||||
}
|
||||
|
||||
return result.join(' ');
|
||||
|
||||
+17
-1
@@ -38,7 +38,23 @@ function convertSVGBufferToPNG(buf, dest) {
|
||||
});
|
||||
}
|
||||
|
||||
// Converts a inline data: to png file
|
||||
function convertInlinePNG(source, dest) {
|
||||
if (!/^data\:image\/png/.test(source)) return Promise.reject(new Error('Source is not a PNG data-uri'));
|
||||
|
||||
var base64data = source.split('data:image/png;base64,')[1];
|
||||
var buf = new Buffer(base64data, 'base64');
|
||||
|
||||
return fs.writeFile(dest, buf)
|
||||
.then(function() {
|
||||
if (fs.existsSync(dest)) return;
|
||||
|
||||
throw new Error('Error converting '+source+' into '+dest);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
convertSVGToPNG: convertSVGToPNG,
|
||||
convertSVGBufferToPNG: convertSVGBufferToPNG
|
||||
convertSVGBufferToPNG: convertSVGBufferToPNG,
|
||||
convertInlinePNG: convertInlinePNG
|
||||
};
|
||||
+12
-2
@@ -4,7 +4,16 @@ var path = require('path');
|
||||
// Is the url an external url
|
||||
function isExternal(href) {
|
||||
try {
|
||||
return Boolean(url.parse(href).protocol);
|
||||
return Boolean(url.parse(href).protocol) && !isDataURI(href);
|
||||
} catch(err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Is the url an iniline data-uri
|
||||
function isDataURI(href) {
|
||||
try {
|
||||
return Boolean(url.parse(href).protocol) && (url.parse(href).protocol === 'data:');
|
||||
} catch(err) {
|
||||
return false;
|
||||
}
|
||||
@@ -39,7 +48,7 @@ function normalize(s) {
|
||||
@return {String}
|
||||
*/
|
||||
function toAbsolute(_href, dir, outdir) {
|
||||
if (isExternal(_href)) return _href;
|
||||
if (isExternal(_href) || isDataURI(_href)) return _href;
|
||||
outdir = outdir == undefined? dir : outdir;
|
||||
|
||||
_href = normalize(_href);
|
||||
@@ -97,6 +106,7 @@ function areIdenticalPaths(p1, p2) {
|
||||
|
||||
module.exports = {
|
||||
areIdenticalPaths: areIdenticalPaths,
|
||||
isDataURI: isDataURI,
|
||||
isExternal: isExternal,
|
||||
isRelative: isRelative,
|
||||
isAnchor: isAnchor,
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
var Q = require('q');
|
||||
var Immutable = require('immutable');
|
||||
|
||||
// Debugging for long stack traces
|
||||
if (global.__DEV__ || process.env.DEBUG) {
|
||||
Q.longStackSupport = true;
|
||||
}
|
||||
|
||||
/**
|
||||
Reduce an array to a promise
|
||||
|
||||
|
||||
+16
-14
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gitbook",
|
||||
"version": "3.0.0-pre.10",
|
||||
"version": "3.0.0-pre.11",
|
||||
"homepage": "https://www.gitbook.com",
|
||||
"description": "Library and cmd utility to generate GitBooks",
|
||||
"main": "lib/index.js",
|
||||
@@ -18,23 +18,22 @@
|
||||
"error": "7.0.2",
|
||||
"escape-html": "^1.0.3",
|
||||
"escape-string-regexp": "1.0.5",
|
||||
"eslint": "^2.2.0",
|
||||
"extend": "^3.0.0",
|
||||
"fresh-require": "1.0.3",
|
||||
"front-matter": "2.0.7",
|
||||
"gitbook-asciidoc": "1.1.0",
|
||||
"gitbook-markdown": "1.2.0",
|
||||
"gitbook-asciidoc": "1.1.4",
|
||||
"gitbook-markdown": "1.2.3",
|
||||
"gitbook-plugin-fontsettings": "1.0.3",
|
||||
"gitbook-plugin-highlight": "2.0.2",
|
||||
"gitbook-plugin-livereload": "0.0.1",
|
||||
"gitbook-plugin-lunr": "1.0.0",
|
||||
"gitbook-plugin-lunr": "1.1.0",
|
||||
"gitbook-plugin-search": "2.2.1",
|
||||
"gitbook-plugin-sharing": "1.0.2",
|
||||
"gitbook-plugin-theme-default": "1.0.0-pre.9",
|
||||
"github-slugid": "1.0.1",
|
||||
"graceful-fs": "4.1.3",
|
||||
"i18n-t": "1.0.0",
|
||||
"ignore": "3.1.1",
|
||||
"ignore": "3.1.2",
|
||||
"immutable": "^3.8.1",
|
||||
"is": "^3.1.0",
|
||||
"json-schema-defaults": "0.1.1",
|
||||
@@ -42,16 +41,16 @@
|
||||
"juice": "1.10.0",
|
||||
"merge-defaults": "0.2.1",
|
||||
"mkdirp": "0.5.1",
|
||||
"moment": "2.12.0",
|
||||
"npm": "3.8.6",
|
||||
"npmi": "1.0.1",
|
||||
"moment": "2.13.0",
|
||||
"npm": "3.8.8",
|
||||
"npmi": "2.0.1",
|
||||
"nunjucks": "2.4.2",
|
||||
"nunjucks-do": "1.0.0",
|
||||
"object-path": "^0.9.2",
|
||||
"omit-keys": "^0.1.0",
|
||||
"q": "1.4.1",
|
||||
"read-installed": "^4.0.3",
|
||||
"request": "2.70.0",
|
||||
"request": "2.72.0",
|
||||
"resolve": "1.1.7",
|
||||
"rmdir": "1.2.0",
|
||||
"semver": "5.1.0",
|
||||
@@ -59,11 +58,11 @@
|
||||
"spawn-cmd": "0.0.2",
|
||||
"tiny-lr": "0.2.1",
|
||||
"tmp": "0.0.28",
|
||||
"urijs": "1.17.1"
|
||||
"urijs": "1.18.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "2.7.0",
|
||||
"jest-cli": "^11.0.2"
|
||||
"eslint": "2.9.0",
|
||||
"jest-cli": "12.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node_modules/.bin/jest --bail",
|
||||
@@ -98,6 +97,9 @@
|
||||
],
|
||||
"jest": {
|
||||
"automock": false,
|
||||
"setupTestFrameworkScriptFile": "<rootDir>/jest/customMatchers.js"
|
||||
"setupTestFrameworkScriptFile": "<rootDir>/jest/customMatchers.js",
|
||||
"globals": {
|
||||
"__DEV__": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user