Compare commits

...

36 Commits

Author SHA1 Message Date
Johan Preynat ad425b9772 Bump version to 3.2.2 2016-10-01 22:35:54 +02:00
Johan Preynat 5238fa352c Rollback to use gitbook-markdown@1.3.2 2016-10-01 22:30:43 +02:00
Johan Preynat 32183b6650 Merge branch 'fix-3.1-version' 2016-10-01 21:49:06 +02:00
Johan Preynat cb3d6a7f01 Correctly handle page parsing errors 2016-10-01 21:47:25 +02:00
Johan Preynat c978f0ab21 Add comment 2016-10-01 21:47:08 +02:00
Samy Pessé 33ff60cee7 Add changes for 3.2.1 2016-09-28 15:56:36 +02:00
Samy Pesse 33d7e022e6 Bump version to 3.2.1 2016-09-28 13:21:24 +02:00
Samy Pesse 09782b964b Update theme-default@1.0.6 2016-09-28 13:10:47 +02:00
Johan Preynat 7938ee8ec6 Use nunjucks@2.5.2 2016-09-28 10:32:14 +02:00
Peter B Smith 2e8e4f63d7 fixing a typo of the word "publishing" (#1536) 2016-09-28 09:49:29 +02:00
jdaviescoates b9fa6c3051 Update examples.md (#1522)
By adding the Loomio and Enspiral handbook examples
2016-09-08 20:38:59 +02:00
Samy Pessé 9c071dade5 Merge pull request #1481 from mcveat/patch-1
Fixed typo
2016-08-04 00:19:11 +02:00
Piotr Adamski 56e44651fa Fixed typo 2016-08-03 22:08:12 +02:00
Samy Pessé 42fac98992 Fix command for getting gitbook version 2016-08-01 09:47:31 +02:00
Samy Pessé 4f5513add0 Create template for GitHub issues 2016-07-25 20:39:31 +02:00
Samy Pesse 90cbfc0596 Add OSX testing on Travis 2016-07-15 11:38:58 +02:00
Samy Pessé 38ab9fa05a Bump version to 3.2.0 2016-07-11 16:48:13 +02:00
Samy Pessé 12e20c5fcc Update theme-default@1.0.5 2016-07-11 16:47:16 +02:00
Samy Pessé 6b103f4532 Fix #1408: fix i18n in website generator and add tests for it 2016-07-11 16:27:22 +02:00
Soreine d4fa5c18a8 editPlugin and getPluginConfig 2016-07-11 15:18:35 +02:00
Soreine 2a116dfdb0 Fix reducedObject when default property is undefined 2016-07-11 15:18:35 +02:00
Samy Pessé 0349f54f3c Export file model 2016-07-07 16:41:05 +02:00
Samy Pessé 695bda312c Bump version to 3.2.0-pre.1 2016-07-05 17:15:48 +02:00
Samy Pessé 144bd4c97a Update gitbook-markdown@2.0.1 2016-07-05 11:07:51 +02:00
Samy Pessé e105983cf8 Add back property "output" to page/template context 2016-07-04 18:08:44 +02:00
Soreine ea3afbed75 Update gitbook-plugin-lunr@1.2.0 2016-07-01 17:52:15 +02:00
Soreine d563abe3df Reduce size of logo to give room to version number 2016-06-30 15:37:31 +02:00
Soreine 70fd4ded29 Update theme-official for doc 2016-06-30 12:15:50 +02:00
Samy Pessé 9ce9388dfc Bump version to 3.2.0-pre.0 2016-06-30 11:09:18 +02:00
Samy Pessé c575ad83ae Update gitbook-markdown@2.0.0 2016-06-30 10:51:46 +02:00
Samy Pessé 936fa1545b Add tests for locationUtils.flatten 2016-06-29 10:32:49 +02:00
Samy Pessé c9c2dde2b6 Add method "isFile" and "isReadme" in SummaryArticle 2016-06-29 10:31:06 +02:00
Samy Pessé d9a1d387c7 Merge pull request #1397 from mpfeil/master
add open and browser args to serve command
2016-06-23 11:40:05 +02:00
Matthias Pfeil bf29d187c8 disable open by default 2016-06-20 17:24:08 +02:00
Matthias Pfeil d86f9b2667 add open and browser args to serve command 2016-06-17 16:00:53 +02:00
Samy Pesse aca4313fc3 Enable long stack support when process.env.CI is true 2016-06-11 12:38:19 +02:00
43 changed files with 533 additions and 238 deletions
+19
View File
@@ -0,0 +1,19 @@
Thank you for giving us your feedback! We listed some guidelines to help you:
If possible, open separate issues for each bug report. Avoid grouping bugs that are unrelated.
### What is the current behavior?
If the current behavior is a bug, please provide the steps to reproduce. if possible, provide the GitBook version being used (`gitbook -V`) and the system infromations (OS and version).
### What is the expected behavior?
How do you think, or how would you like it should behave.
#### For GitBook.com
Provide, if possible, your username and the URL of the concerned book.
----
The GitBook Team
+3
View File
@@ -1,5 +1,8 @@
sudo: false sudo: false
language: node_js language: node_js
os:
- linux
- osx
node_js: node_js:
- "stable" - "stable"
- "4.1" - "4.1"
+17
View File
@@ -2,6 +2,23 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/). This project adheres to [Semantic Versioning](http://semver.org/).
## 3.2.2
- Fix catching parsing errors leading to possible missing pages in generated book
- Rollback markdown parser to `kramed` until `markup-it` is stable enough
## 3.2.1
- Fix bug on Firefox when navigating to an url containing an hash
- Update nunjucks to fix JS error when page contains a lot of templating blocks
## 3.2.0
- Switch markdown parser from `kramed` to `markup-it`
- Fix support of `|` in tables
- Fix access to `output.name` in templating
- Fix i18n for website and PDF
- Fix minor scrolling issues on website
- Improve options of default search indexer (keywords, disabling per pages)
- Improve pertinence of search results
## 3.1.1 ## 3.1.1
- Fix order of plugins during loading - Fix order of plugins during loading
- Fix error when using math and conrefs - Fix error when using math and conrefs
+2 -2
View File
@@ -6,10 +6,10 @@ module.exports = {
title: 'GitBook Toolchain Documentation', title: 'GitBook Toolchain Documentation',
// Enforce use of GitBook v3 // Enforce use of GitBook v3
gitbook: '>=3.0.0-pre.0', gitbook: '3.1.1',
// Use the "official" theme // Use the "official" theme
plugins: ['theme-official', 'sitemap'], plugins: ['theme-official@2.1.1', '-sharing', '-fontsettings', 'sitemap'],
variables: { variables: {
version: pkg.version version: pkg.version
+2
View File
@@ -23,5 +23,7 @@ More than 50,000 books have been published on [GitBook.com](https://www.gitbook.
### Documentation ### Documentation
- [DuckDuckHack Documentation](http://docs.duckduckhack.com) by [DuckDuckGo](https://duckduckgo.com/about) - [DuckDuckHack Documentation](http://docs.duckduckhack.com) by [DuckDuckGo](https://duckduckgo.com/about)
- [Loomio Handbook](http://loomio.coop/) by [Loomio](https://www.loomio.org/)
- [Enspiral Handbook](http://handbook.enspiral.com/) by [Enspiral](http://enspiral.com/)
- This documentation - This documentation
+2 -2
View File
@@ -2,7 +2,7 @@
### Testing your plugin locally ### Testing your plugin locally
Testing your plugin on your book before plushing it is possible using [npm link](https://docs.npmjs.com/cli/link). Testing your plugin on your book before publishing it is possible using [npm link](https://docs.npmjs.com/cli/link).
In the plugin's folder, run: In the plugin's folder, run:
@@ -10,7 +10,7 @@ In the plugin's folder, run:
$ npm link $ npm link
``` ```
The nin your book's folder: Then in your book's folder:
``` ```
$ npm link gitbook-plugin-<plugin's name> $ npm link gitbook-plugin-<plugin's name>
+4
View File
@@ -0,0 +1,4 @@
/* Reduce size of logo to allow long versions like 3.0.0-pre.1 */
.gb-page-header .container .logo h1 {
font-size: 24px ;
}
+1
View File
@@ -6,6 +6,7 @@ module.exports = {
// Models // Models
Book: require('./models/book'), Book: require('./models/book'),
FS: require('./models/fs'), FS: require('./models/fs'),
File: require('./models/file'),
Summary: require('./models/summary'), Summary: require('./models/summary'),
Glossary: require('./models/glossary'), Glossary: require('./models/glossary'),
Config: require('./models/config'), Config: require('./models/config'),
+17
View File
@@ -1,6 +1,7 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
var tinylr = require('tiny-lr'); var tinylr = require('tiny-lr');
var open = require('open');
var Parse = require('../parse'); var Parse = require('../parse');
var Output = require('../output'); var Output = require('../output');
@@ -32,9 +33,11 @@ function generateBook(args, kwargs) {
var outputFolder = getOutputFolder(args); var outputFolder = getOutputFolder(args);
var book = getBook(args, kwargs); var book = getBook(args, kwargs);
var Generator = Output.getGenerator(kwargs.format); var Generator = Output.getGenerator(kwargs.format);
var browser = kwargs['browser'];
var hasWatch = kwargs['watch']; var hasWatch = kwargs['watch'];
var hasLiveReloading = kwargs['live']; var hasLiveReloading = kwargs['live'];
var hasOpen = kwargs['open'];
// Stop server if running // Stop server if running
if (server.isRunning()) console.log('Stopping server'); if (server.isRunning()) console.log('Stopping server');
@@ -71,6 +74,10 @@ function generateBook(args, kwargs) {
} }
}); });
} }
if (hasOpen) {
open('http://localhost:'+port, browser);
}
}) })
.then(function() { .then(function() {
if (!hasWatch) { if (!hasWatch) {
@@ -112,6 +119,16 @@ module.exports = {
description: 'Enable live reloading', description: 'Enable live reloading',
defaults: true defaults: true
}, },
{
name: 'open',
description: 'Enable opening book in browser',
defaults: false
},
{
name: 'browser',
description: 'Specify browser for opening book',
defaults: ''
},
options.log, options.log,
options.format options.format
], ],
+4
View File
@@ -18,6 +18,10 @@ module.exports = {
'type': 'string', 'type': 'string',
'title': 'ISBN for published book' 'title': 'ISBN for published book'
}, },
'language': {
'type': 'string',
'title': 'Language of the book'
},
'author': { 'author': {
'type': 'string', 'type': 'string',
'title': 'Name of the author' 'title': 'Name of the author'
+6 -6
View File
@@ -3,12 +3,12 @@ var encodePage = require('./encodePage');
var encodeFile = require('./encodeFile'); var encodeFile = require('./encodeFile');
/** /**
Return a JSON representation of a book with a specific file * Return a JSON representation of a book with a specific file
*
@param {Book} output * @param {Book} output
@param {Page} page * @param {Page} page
@return {Object} * @return {Object}
*/ */
function encodeBookWithPage(book, page) { function encodeBookWithPage(book, page) {
var file = page.getFile(); var file = page.getFile();
+5 -5
View File
@@ -1,11 +1,11 @@
var encodeBook = require('./encodeBook'); var encodeBook = require('./encodeBook');
/** /**
Encode an output to JSON * Encode an output to JSON
*
@param {Output} * @param {Output}
@return {Object} * @return {Object}
*/ */
function encodeOutputToJson(output) { function encodeOutputToJson(output) {
var book = output.getBook(); var book = output.getBook();
var generator = output.getGenerator(); var generator = output.getGenerator();
+23
View File
@@ -0,0 +1,23 @@
var encodeOutput = require('./encodeOutput');
var encodePage = require('./encodePage');
var encodeFile = require('./encodeFile');
/**
* Return a JSON representation of a book with a specific file
*
* @param {Book} output
* @param {Page} page
* @return {Object}
*/
function encodeOutputWithPage(output, page) {
var file = page.getFile();
var book = output.getBook();
var result = encodeOutput(output);
result.page = encodePage(page, book.getSummary());
result.file = encodeFile(file);
return result;
}
module.exports = encodeOutputWithPage;
+1
View File
@@ -2,6 +2,7 @@
module.exports = { module.exports = {
encodeOutput: require('./encodeOutput'), encodeOutput: require('./encodeOutput'),
encodeBookWithPage: require('./encodeBookWithPage'), encodeBookWithPage: require('./encodeBookWithPage'),
encodeOutputWithPage: require('./encodeOutputWithPage'),
encodeBook: require('./encodeBook'), encodeBook: require('./encodeBook'),
encodeFile: require('./encodeFile'), encodeFile: require('./encodeFile'),
encodePage: require('./encodePage'), encodePage: require('./encodePage'),
+30
View File
@@ -1,4 +1,5 @@
var SummaryArticle = require('../summaryArticle'); var SummaryArticle = require('../summaryArticle');
var File = require('../file');
describe('SummaryArticle', function() { describe('SummaryArticle', function() {
describe('createChildLevel', function() { describe('createChildLevel', function() {
@@ -18,6 +19,35 @@ describe('SummaryArticle', function() {
expect(article.createChildLevel()).toBe('1.1.2'); expect(article.createChildLevel()).toBe('1.1.2');
}); });
}); });
describe('isFile', function() {
it('must return true when exactly the file', function() {
var article = SummaryArticle.create({
ref: 'hello.md'
}, '1.1');
var file = File.createWithFilepath('hello.md');
expect(article.isFile(file)).toBe(true);
});
it('must return true when path is not normalized', function() {
var article = SummaryArticle.create({
ref: '/hello.md'
}, '1.1');
var file = File.createWithFilepath('hello.md');
expect(article.isFile(file)).toBe(true);
});
it('must return false when has anchor', function() {
var article = SummaryArticle.create({
ref: 'hello.md#world'
}, '1.1');
var file = File.createWithFilepath('hello.md');
expect(article.isFile(file)).toBe(false);
});
});
}); });
+30 -3
View File
@@ -40,7 +40,8 @@ SummaryArticle.prototype.getDepth = function() {
}; };
/** /**
* Get path (without anchor) to the pointing file * Get path (without anchor) to the pointing file.
* It also normalizes the file path.
* *
* @return {String} * @return {String}
*/ */
@@ -58,8 +59,8 @@ SummaryArticle.prototype.getPath = function() {
var pathname = (parts.length > 1? parts.slice(0, -1).join('#') : ref); var pathname = (parts.length > 1? parts.slice(0, -1).join('#') : ref);
// Normalize path to remove ('./', etc) // Normalize path to remove ('./', '/...', etc)
return location.normalize(pathname); return location.flatten(pathname);
}; };
/** /**
@@ -106,6 +107,32 @@ SummaryArticle.prototype.isPage = function() {
return !this.isExternal() && this.getRef(); return !this.isExternal() && this.getRef();
}; };
/**
* Check if this article is a file (exatcly)
*
* @param {File} file
* @return {Boolean}
*/
SummaryArticle.prototype.isFile = function(file) {
return (
file.getPath() === this.getPath()
&& this.getAnchor() === undefined
);
};
/**
* Check if this article is the introduction of the book
*
* @param {Book|Readme} book
* @return {Boolean}
*/
SummaryArticle.prototype.isReadme = function(book) {
var readme = book.getFile? book : book.getReadme();
var file = readme.getFile();
return this.isFile(file);
};
/** /**
* Is article pointing to aan absolute url * Is article pointing to aan absolute url
* *
+1 -1
View File
@@ -7,7 +7,7 @@
* @return {Config} * @return {Config}
*/ */
function editPlugin(config, pluginName, pluginConfig) { function editPlugin(config, pluginName, pluginConfig) {
return config.set('pluginsConfig.'+pluginName, pluginConfig); return config.setValue('pluginsConfig.'+pluginName, pluginConfig);
} }
module.exports = editPlugin; module.exports = editPlugin;
+20
View File
@@ -0,0 +1,20 @@
/**
* Return the configuration for a plugin
* @param {Config} config
* @param {String} pluginName
* @return {Object}
*/
function getPluginConfig(config, pluginName) {
var pluginsConfig = config.getValues().get('pluginsConfig');
if (pluginsConfig === undefined) {
return {};
}
var pluginConf = pluginsConfig.get(pluginName);
if (pluginConf === undefined) {
return {};
} else {
return pluginConf.toJS();
}
}
module.exports = getPluginConfig;
+1
View File
@@ -5,5 +5,6 @@ module.exports = {
togglePlugin: require('./togglePlugin'), togglePlugin: require('./togglePlugin'),
editPlugin: require('./editPlugin'), editPlugin: require('./editPlugin'),
hasPlugin: require('./hasPlugin'), hasPlugin: require('./hasPlugin'),
getPluginConfig: require('./getPluginConfig'),
isDefaultPlugin: require('./isDefaultPlugin') isDefaultPlugin: require('./isDefaultPlugin')
}; };
+38
View File
@@ -0,0 +1,38 @@
var Immutable = require('immutable');
var Output = require('../../models/output');
var Book = require('../../models/book');
var parseBook = require('../../parse/parseBook');
var createMockFS = require('../../fs/mock');
var preparePlugins = require('../preparePlugins');
/**
* Create an output using a generator
*
* FOR TESTING PURPOSE ONLY
*
* @param {Generator} generator
* @param {Map<String:String|Map>} files
* @return {Promise<Output>}
*/
function createMockOutput(generator, files, options) {
var fs = createMockFS(files);
var book = Book.createForFS(fs);
var state = generator.State? generator.State({}) : Immutable.Map();
book = book.setLogLevel('disabled');
options = generator.Options(options);
return parseBook(book)
.then(function(resultBook) {
return new Output({
book: resultBook,
options: options,
state: state,
generator: generator.name
});
})
.then(preparePlugins);
}
module.exports = createMockOutput;
+1 -1
View File
@@ -1,4 +1,4 @@
var generateMock = require('../generateMock'); var generateMock = require('./generateMock');
var EbookGenerator = require('../ebook'); var EbookGenerator = require('../ebook');
describe('EbookGenerator', function() { describe('EbookGenerator', function() {
@@ -1,21 +1,20 @@
var tmp = require('tmp'); var tmp = require('tmp');
var Book = require('../models/book'); var Book = require('../../models/book');
var createMockFS = require('../fs/mock'); var createMockFS = require('../../fs/mock');
var parseBook = require('../parse/parseBook'); var parseBook = require('../../parse/parseBook');
var generateBook = require('./generateBook'); var generateBook = require('../generateBook');
/** /**
Generate a book using JSON generator * Generate a book using a generator
And returns the path to the output dir. * And returns the path to the output dir.
*
FOR TESTING PURPOSE ONLY * FOR TESTING PURPOSE ONLY
*
@param {Generator} * @param {Generator}
@param {Map<String:String|Map>} files * @param {Map<String:String|Map>} files
@return {Promise<String>} * @return {Promise<String>}
*/ */
function generateMock(Generator, files) { function generateMock(Generator, files) {
var fs = createMockFS(files); var fs = createMockFS(files);
var book = Book.createForFS(fs); var book = Book.createForFS(fs);
+1 -1
View File
@@ -1,4 +1,4 @@
var generateMock = require('../generateMock'); var generateMock = require('./generateMock');
var JSONGenerator = require('../json'); var JSONGenerator = require('../json');
describe('JSONGenerator', function() { describe('JSONGenerator', function() {
+1 -1
View File
@@ -1,5 +1,5 @@
var fs = require('fs'); var fs = require('fs');
var generateMock = require('../generateMock'); var generateMock = require('./generateMock');
var WebsiteGenerator = require('../website'); var WebsiteGenerator = require('../website');
describe('WebsiteGenerator', function() { describe('WebsiteGenerator', function() {
+26 -28
View File
@@ -13,13 +13,12 @@ var generateAssets = require('./generateAssets');
var generatePages = require('./generatePages'); var generatePages = require('./generatePages');
/** /**
Process an output to generate the book * Process an output to generate the book
*
@param {Generator} generator * @param {Generator} generator
@param {Output} output * @param {Output} output
* @return {Promise<Output>}
@return {Promise<Output>} */
*/
function processOutput(generator, startOutput) { function processOutput(generator, startOutput) {
return Promise(startOutput) return Promise(startOutput)
.then(preparePlugins) .then(preparePlugins)
@@ -133,27 +132,26 @@ function processOutput(generator, startOutput) {
} }
/** /**
Generate a book using a generator. * Generate a book using a generator.
*
The overall process is: * The overall process is:
1. List and load plugins for this book * 1. List and load plugins for this book
2. Call hook "config" * 2. Call hook "config"
3. Call hook "init" * 3. Call hook "init"
4. Initialize generator * 4. Initialize generator
5. List all assets and pages * 5. List all assets and pages
6. Copy all assets to output * 6. Copy all assets to output
7. Generate all pages * 7. Generate all pages
8. Call hook "finish:before" * 8. Call hook "finish:before"
9. Finish generation * 9. Finish generation
10. Call hook "finish" * 10. Call hook "finish"
*
*
@param {Generator} generator * @param {Generator} generator
@param {Book} book * @param {Book} book
@param {Object} options * @param {Object} options
* @return {Promise<Output>}
@return {Promise<Output>} */
*/
function generateBook(generator, book, options) { function generateBook(generator, book, options) {
options = generator.Options(options); options = generator.Options(options);
var state = generator.State? generator.State({}) : Immutable.Map(); var state = generator.State? generator.State({}) : Immutable.Map();
+7 -7
View File
@@ -10,12 +10,12 @@ var createTemplateEngine = require('./createTemplateEngine');
var callPageHook = require('./callPageHook'); var callPageHook = require('./callPageHook');
/** /**
Prepare and generate HTML for a page * Prepare and generate HTML for a page
*
@param {Output} output * @param {Output} output
@param {Page} page * @param {Page} page
@return {Promise<Page>} * @return {Promise<Page>}
*/ */
function generatePage(output, page) { function generatePage(output, page) {
var book = output.getBook(); var book = output.getBook();
var engine = createTemplateEngine(output); var engine = createTemplateEngine(output);
@@ -27,7 +27,7 @@ function generatePage(output, page) {
var file = resultPage.getFile(); var file = resultPage.getFile();
var filePath = file.getPath(); var filePath = file.getPath();
var parser = file.getParser(); var parser = file.getParser();
var context = JSONUtils.encodeBookWithPage(book, resultPage); var context = JSONUtils.encodeOutputWithPage(output, resultPage);
if (!parser) { if (!parser) {
return Promise.reject(error.FileNotParsableError({ return Promise.reject(error.FileNotParsableError({
+5 -5
View File
@@ -9,11 +9,11 @@ var fileToOutput = require('./helper/fileToOutput');
var CODEBLOCK = 'code'; var CODEBLOCK = 'code';
/** /**
Return default modifier to prepare a page for * Return default modifier to prepare a page for
rendering. * rendering.
*
@return {Array<Modifier>} * @return {Array<Modifier>}
*/ */
function getModifiers(output, page) { function getModifiers(output, page) {
var book = output.getBook(); var book = output.getBook();
var plugins = output.getPlugins(); var plugins = output.getPlugins();
+6 -6
View File
@@ -6,12 +6,12 @@ var LocationUtils = require('../../utils/location');
var OUTPUT_EXTENSION = '.html'; var OUTPUT_EXTENSION = '.html';
/** /**
Convert a filePath (absolute) to a filename for output * Convert a filePath (absolute) to a filename for output
*
@param {Output} output * @param {Output} output
@param {String} filePath * @param {String} filePath
@return {String} * @return {String}
*/ */
function fileToOutput(output, filePath) { function fileToOutput(output, filePath) {
var book = output.getBook(); var book = output.getBook();
var readme = book.getReadme(); var readme = book.getReadme();
+6 -6
View File
@@ -3,12 +3,12 @@ var LocationUtils = require('../../utils/location');
var fileToURL = require('./fileToURL'); var fileToURL = require('./fileToURL');
/** /**
Resolve an absolute path (extracted from a link) * Resolve an absolute path (extracted from a link)
*
@param {Output} output * @param {Output} output
@param {String} filePath * @param {String} filePath
@return {String} * @return {String}
*/ */
function resolveFileToURL(output, filePath) { function resolveFileToURL(output, filePath) {
// Convert /test.png -> test.png // Convert /test.png -> test.png
filePath = LocationUtils.toAbsolute(filePath, '', ''); filePath = LocationUtils.toAbsolute(filePath, '', '');
+5 -5
View File
@@ -7,11 +7,11 @@ var getModifiers = require('../getModifiers');
var JSON_VERSION = '3'; var JSON_VERSION = '3';
/** /**
Write a page as a json file * Write a page as a json file
*
@param {Output} output * @param {Output} output
@param {Page} page * @param {Page} page
*/ */
function onPage(output, page) { function onPage(output, page) {
var file = page.getFile(); var file = page.getFile();
var readme = output.getBook().getReadme().getFile(); var readme = output.getBook().getReadme().getFile();
+9 -10
View File
@@ -59,19 +59,18 @@ function replaceText($, el, search, replace, text_only ) {
} }
/** /**
Annotate text using a list of GlossaryEntry * Annotate text using a list of GlossaryEntry
*
@param {List<GlossaryEntry>} * @param {List<GlossaryEntry>}
@param {String} glossaryFilePath * @param {String} glossaryFilePath
@param {HTMLDom} $ * @param {HTMLDom} $
*/ */
function annotateText(entries, glossaryFilePath, $) { function annotateText(entries, glossaryFilePath, $) {
entries.forEach(function(entry) { entries.forEach(function(entry) {
var entryId = entry.getID(); var entryId = entry.getID();
var name = entry.getName(); var name = entry.getName();
var description = entry.getDescription(); var description = entry.getDescription();
var searchRegex = new RegExp( '\\b(' + pregQuote(name.toLowerCase()) + ')\\b' , 'gi' );
var searchRegex = new RegExp( '\\b(' + pregQuote(name.toLowerCase()) + ')\\b' , 'gi' );
$('*').each(function() { $('*').each(function() {
var $this = $(this); var $this = $(this);
+5 -5
View File
@@ -2,11 +2,11 @@ var Plugins = require('../plugins');
var Promise = require('../utils/promise'); var Promise = require('../utils/promise');
/** /**
Load and setup plugins * Load and setup plugins
*
@param {Output} * @param {Output}
@return {Promise<Output>} * @return {Promise<Output>}
*/ */
function preparePlugins(output) { function preparePlugins(output) {
var book = output.getBook(); var book = output.getBook();
+38
View File
@@ -0,0 +1,38 @@
var createMockOutput = require('../../__tests__/createMock');
var prepareI18n = require('../prepareI18n');
var createTemplateEngine = require('../createTemplateEngine');
var WebsiteGenerator = require('../');
describe('i18n', function() {
it('should correctly use english as default language', function() {
return createMockOutput(WebsiteGenerator, {
'README.md': 'Hello World'
})
.then(function(output) {
return prepareI18n(output);
})
.then(function(output) {
var engine = createTemplateEngine(output, 'README.md');
var t = engine.getFilters().get('t');
expect(t('SUMMARY_INTRODUCTION')).toEqual('Introduction');
});
});
it('should correctly use language from book.json', function() {
return createMockOutput(WebsiteGenerator, {
'README.md': 'Hello World',
'book.json': JSON.stringify({ language: 'fr' })
})
.then(function(output) {
return prepareI18n(output);
})
.then(function(output) {
var engine = createTemplateEngine(output, 'README.md');
var t = engine.getFilters().get('t');
expect(t('GITBOOK_LINK')).toEqual('Publié avec GitBook');
});
});
});
+27 -31
View File
@@ -18,19 +18,19 @@ var fileToURL = require('../helper/fileToURL');
var resolveFileToURL = require('../helper/resolveFileToURL'); var resolveFileToURL = require('../helper/resolveFileToURL');
/** /**
Directory for a theme with the templates * Directory for a theme with the templates
*/ */
function templateFolder(dir) { function templateFolder(dir) {
return path.join(dir, templatesFolder); return path.join(dir, templatesFolder);
} }
/** /**
Create templating engine to render themes * Create templating engine to render themes
*
@param {Output} output * @param {Output} output
@param {String} currentFile * @param {String} currentFile
@return {TemplateEngine} * @return {TemplateEngine}
*/ */
function createTemplateEngine(output, currentFile) { function createTemplateEngine(output, currentFile) {
var book = output.getBook(); var book = output.getBook();
var state = output.getState(); var state = output.getState();
@@ -47,18 +47,17 @@ function createTemplateEngine(output, currentFile) {
var loader = new Templating.ThemesLoader(tplSearchPaths); var loader = new Templating.ThemesLoader(tplSearchPaths);
// Get languages // Get languages
var language = config.get('language'); var language = config.getValue('language');
// Create API context // Create API context
var context = Api.encodeGlobal(output); var context = Api.encodeGlobal(output);
/** /**
Check if a file exists * Check if a file exists
* @param {String} fileName
@param {String} fileName * @return {Boolean}
@return {Boolean} */
*/
function fileExists(fileName) { function fileExists(fileName) {
if (!fileName) { if (!fileName) {
return false; return false;
@@ -69,11 +68,10 @@ function createTemplateEngine(output, currentFile) {
} }
/** /**
Return an article by its path * Return an article by its path
* @param {String} filePath
@param {String} filePath * @return {Object|undefined}
@return {Object|undefined} */
*/
function getArticleByPath(filePath) { function getArticleByPath(filePath) {
var article = summary.getByPath(filePath); var article = summary.getByPath(filePath);
if (!article) return undefined; if (!article) return undefined;
@@ -82,11 +80,10 @@ function createTemplateEngine(output, currentFile) {
} }
/** /**
Return a page by its path * Return a page by its path
* @param {String} filePath
@param {String} filePath * @return {Object|undefined}
@return {Object|undefined} */
*/
function getPageByPath(filePath) { function getPageByPath(filePath) {
var page = output.getPage(filePath); var page = output.getPage(filePath);
if (!page) return undefined; if (!page) return undefined;
@@ -94,7 +91,6 @@ function createTemplateEngine(output, currentFile) {
return JSONUtils.encodePage(page, summary); return JSONUtils.encodePage(page, summary);
} }
return TemplateEngine.create({ return TemplateEngine.create({
loader: loader, loader: loader,
@@ -108,17 +104,17 @@ function createTemplateEngine(output, currentFile) {
filters: defaultFilters.merge({ filters: defaultFilters.merge({
/** /**
Translate a sentence * Translate a sentence
*/ */
t: function t(s) { t: function t(s) {
return i18n.t(language, s); return i18n.t(language, s);
}, },
/** /**
Resolve an absolute file path into a * Resolve an absolute file path into a
relative path. * relative path.
it also resolve pages * it also resolve pages
*/ */
resolveFile: function(filePath) { resolveFile: function(filePath) {
filePath = resolveFileToURL(output, filePath); filePath = resolveFileToURL(output, filePath);
return LocationUtils.relativeForFile(currentFile, filePath); return LocationUtils.relativeForFile(currentFile, filePath);
+6 -6
View File
@@ -12,11 +12,11 @@ var createTemplateEngine = require('./createTemplateEngine');
var fileToOutput = require('../helper/fileToOutput'); var fileToOutput = require('../helper/fileToOutput');
/** /**
Write a page as a json file * Write a page as a json file
*
@param {Output} output * @param {Output} output
@param {Page} page * @param {Page} page
*/ */
function onPage(output, page) { function onPage(output, page) {
var options = output.getOptions(); var options = output.getOptions();
var prefix = options.get('prefix'); var prefix = options.get('prefix');
@@ -40,7 +40,7 @@ function onPage(output, page) {
return Modifiers.modifyHTML(page, getModifiers(output, page)) return Modifiers.modifyHTML(page, getModifiers(output, page))
.then(function(resultPage) { .then(function(resultPage) {
// Generate the context // Generate the context
var context = JSONUtils.encodeBookWithPage(output.getBook(), resultPage); var context = JSONUtils.encodeOutputWithPage(output, resultPage);
context.plugins = { context.plugins = {
resources: Plugins.listResources(plugins, resources).toJS() resources: Plugins.listResources(plugins, resources).toJS()
}; };
+5 -5
View File
@@ -5,11 +5,11 @@ var Promise = require('../../utils/promise');
var listSearchPaths = require('./listSearchPaths'); var listSearchPaths = require('./listSearchPaths');
/** /**
Prepare i18n, load translations from plugins and book * Prepare i18n, load translations from plugins and book
*
@param {Output} * @param {Output}
@return {Promise<Output>} * @return {Promise<Output>}
*/ */
function prepareI18n(output) { function prepareI18n(output) {
var state = output.getState(); var state = output.getState();
var i18n = state.getI18n(); var i18n = state.getI18n();
+1
View File
@@ -9,6 +9,7 @@ var direction = require('direction');
* @return {Page} * @return {Page}
*/ */
function parsePageFromString(page, content) { function parsePageFromString(page, content) {
// Parse page YAML
var parsed = fm(content); var parsed = fm(content);
return page.merge({ return page.merge({
+25 -6
View File
@@ -11,15 +11,26 @@ var parsePage = require('./parsePage');
@param {Book} book @param {Book} book
@param {String} filePath @param {String} filePath
@return {Page} @return {Page?}
*/ */
function parseFilePage(book, filePath) { function parseFilePage(book, filePath) {
var fs = book.getContentFS(); var fs = book.getContentFS();
return fs.statFile(filePath) return fs.statFile(filePath)
.then(function(file) { .then(
var page = Page.createForFile(file); function(file) {
return parsePage(book, page); var page = Page.createForFile(file);
return parsePage(book, page);
},
function(err) {
// file doesn't exist
return null;
}
)
.fail(function(err) {
var logger = book.getLogger();
logger.error.ln('error while parsing page "' + filePath + '":');
throw err;
}); });
} }
@@ -48,9 +59,12 @@ function parsePagesList(book) {
return parseFilePage(book, filepath) return parseFilePage(book, filepath)
.then(function(page) { .then(function(page) {
map = map.set(filepath, page);
}, function() {
// file doesn't exist // file doesn't exist
if (!page) {
return;
}
map = map.set(filepath, page);
}); });
}) })
) )
@@ -65,6 +79,11 @@ function parsePagesList(book) {
return parseFilePage(book, file.getPath()) return parseFilePage(book, file.getPath())
.then(function(page) { .then(function(page) {
// file doesn't exist
if (!page) {
return;
}
map = map.set(file.getPath(), page); map = map.set(file.getPath(), page);
}); });
}) })
+15
View File
@@ -39,6 +39,21 @@ describe('LocationUtils', function() {
}); });
}); });
describe('.flatten', function() {
it('should remove leading slash', function() {
expect(LocationUtils.flatten('/test.md')).toBe('test.md');
expect(LocationUtils.flatten('/hello/cool.md')).toBe('hello/cool.md');
});
it('should remove leading slashes', function() {
expect(LocationUtils.flatten('///test.md')).toBe('test.md');
});
it('should not break paths', function() {
expect(LocationUtils.flatten('hello/cool.md')).toBe('hello/cool.md');
});
});
describe('.toAbsolute', function() { describe('.toAbsolute', function() {
it('should correctly transform as absolute', function() { it('should correctly transform as absolute', function() {
expect(LocationUtils.toAbsolute('http://google.fr')).toBe('http://google.fr'); expect(LocationUtils.toAbsolute('http://google.fr')).toBe('http://google.fr');
+51 -35
View File
@@ -40,13 +40,28 @@ function normalize(s) {
} }
/** /**
Convert a relative path to absolute * Flatten a path, it removes the leading "/"
*
* @param {String} href
* @return {String}
*/
function flatten(href) {
href = normalize(href);
if (href[0] == '/') {
href = normalize(href.slice(1));
}
@param {String} href return href;
@param {String} dir: directory parent of the file currently in rendering process }
@param {String} outdir: directory parent from the html output
@return {String} /**
*/ * Convert a relative path to absolute
*
* @param {String} href
* @param {String} dir: directory parent of the file currently in rendering process
* @param {String} outdir: directory parent from the html output
* @return {String}
*/
function toAbsolute(_href, dir, outdir) { function toAbsolute(_href, dir, outdir) {
if (isExternal(_href) || isDataURI(_href)) { if (isExternal(_href) || isDataURI(_href)) {
return _href; return _href;
@@ -74,50 +89,51 @@ function toAbsolute(_href, dir, outdir) {
} }
/** /**
Convert an absolute path to a relative path for a specific folder (dir) * Convert an absolute path to a relative path for a specific folder (dir)
('test/', 'hello.md') -> '../hello.md' * ('test/', 'hello.md') -> '../hello.md'
*
@param {String} dir: current directory * @param {String} dir: current directory
@param {String} file: absolute path of file * @param {String} file: absolute path of file
@return {String} * @return {String}
*/ */
function relative(dir, file) { function relative(dir, file) {
var isDirectory = file.slice(-1) === '/'; var isDirectory = file.slice(-1) === '/';
return normalize(path.relative(dir, file)) + (isDirectory? '/': ''); return normalize(path.relative(dir, file)) + (isDirectory? '/': '');
} }
/** /**
Convert an absolute path to a relative path for a specific folder (dir) * Convert an absolute path to a relative path for a specific folder (dir)
('test/test.md', 'hello.md') -> '../hello.md' * ('test/test.md', 'hello.md') -> '../hello.md'
*
@param {String} baseFile: current file * @param {String} baseFile: current file
@param {String} file: absolute path of file * @param {String} file: absolute path of file
@return {String} * @return {String}
*/ */
function relativeForFile(baseFile, file) { function relativeForFile(baseFile, file) {
return relative(path.dirname(baseFile), file); return relative(path.dirname(baseFile), file);
} }
/** /**
Compare two paths, return true if they are identical * Compare two paths, return true if they are identical
('README.md', './README.md') -> true * ('README.md', './README.md') -> true
*
@param {String} p1: first path * @param {String} p1: first path
@param {String} p2: second path * @param {String} p2: second path
@return {Boolean} * @return {Boolean}
*/ */
function areIdenticalPaths(p1, p2) { function areIdenticalPaths(p1, p2) {
return normalize(p1) === normalize(p2); return normalize(p1) === normalize(p2);
} }
module.exports = { module.exports = {
areIdenticalPaths: areIdenticalPaths, areIdenticalPaths: areIdenticalPaths,
isDataURI: isDataURI, isDataURI: isDataURI,
isExternal: isExternal, isExternal: isExternal,
isRelative: isRelative, isRelative: isRelative,
isAnchor: isAnchor, isAnchor: isAnchor,
normalize: normalize, normalize: normalize,
toAbsolute: toAbsolute, toAbsolute: toAbsolute,
relative: relative, relative: relative,
relativeForFile: relativeForFile relativeForFile: relativeForFile,
flatten: flatten
}; };
+44 -43
View File
@@ -2,34 +2,35 @@ var Q = require('q');
var Immutable = require('immutable'); var Immutable = require('immutable');
// Debugging for long stack traces // Debugging for long stack traces
if (global.__DEV__ || process.env.DEBUG) { if (process.env.DEBUG || process.env.CI) {
Q.longStackSupport = true; Q.longStackSupport = true;
} }
/** /**
Reduce an array to a promise * Reduce an array to a promise
*
@param {Array|List} arr * @param {Array|List} arr
@param {Function(value, element, index)} * @param {Function(value, element, index)}
@return {Promise<Mixed>} * @return {Promise<Mixed>}
*/ */
function reduce(arr, iter, base) { function reduce(arr, iter, base) {
arr = Immutable.Iterable.isIterable(arr)? arr : Immutable.List(arr); arr = Immutable.Iterable.isIterable(arr)? arr : Immutable.List(arr);
return arr.reduce(function(prev, elem, key) { return arr.reduce(function(prev, elem, key) {
return prev.then(function(val) { return prev
.then(function(val) {
return iter(val, elem, key); return iter(val, elem, key);
}); });
}, Q(base)); }, Q(base));
} }
/** /**
Iterate over an array using an async iter * Iterate over an array using an async iter
*
@param {Array|List} arr * @param {Array|List} arr
@param {Function(value, element, index)} * @param {Function(value, element, index)}
@return {Promise} * @return {Promise}
*/ */
function forEach(arr, iter) { function forEach(arr, iter) {
return reduce(arr, function(val, el, key) { return reduce(arr, function(val, el, key) {
return iter(el, key); return iter(el, key);
@@ -37,12 +38,12 @@ function forEach(arr, iter) {
} }
/** /**
Transform an array * Transform an array
*
@param {Array|List} arr * @param {Array|List} arr
@param {Function(value, element, index)} * @param {Function(value, element, index)}
@return {Promise} * @return {Promise}
*/ */
function serie(arr, iter, base) { function serie(arr, iter, base) {
return reduce(arr, function(before, item, key) { return reduce(arr, function(before, item, key) {
return Q(iter(item, key)) return Q(iter(item, key))
@@ -54,12 +55,12 @@ function serie(arr, iter, base) {
} }
/** /**
Iter over an array and return first result (not null) * Iter over an array and return first result (not null)
*
@param {Array|List} arr * @param {Array|List} arr
@param {Function(element, index)} * @param {Function(element, index)}
@return {Promise<Mixed>} * @return {Promise<Mixed>}
*/ */
function some(arr, iter) { function some(arr, iter) {
arr = Immutable.List(arr); arr = Immutable.List(arr);
@@ -73,12 +74,12 @@ function some(arr, iter) {
} }
/** /**
Map an array using an async (promised) iterator * Map an array using an async (promised) iterator
*
@param {Array|List} arr * @param {Array|List} arr
@param {Function(element, index)} * @param {Function(element, index)}
@return {Promise<List>} * @return {Promise<List>}
*/ */
function mapAsList(arr, iter) { function mapAsList(arr, iter) {
return reduce(arr, function(prev, entry, i) { return reduce(arr, function(prev, entry, i) {
return Q(iter(entry, i)) return Q(iter(entry, i))
@@ -90,12 +91,12 @@ function mapAsList(arr, iter) {
} }
/** /**
Map an array or map * Map an array or map
*
@param {Array|List|Map|OrderedMap} arr * @param {Array|List|Map|OrderedMap} arr
@param {Function(element, key)} * @param {Function(element, key)}
@return {Promise<List|Map|OrderedMap>} * @return {Promise<List|Map|OrderedMap>}
*/ */
function map(arr, iter) { function map(arr, iter) {
if (Immutable.Map.isMap(arr)) { if (Immutable.Map.isMap(arr)) {
var type = 'Map'; var type = 'Map';
@@ -122,11 +123,11 @@ function map(arr, iter) {
/** /**
Wrap a function in a promise * Wrap a function in a promise
*
@param {Function} func * @param {Function} func
@return {Funciton} * @return {Funciton}
*/ */
function wrap(func) { function wrap(func) {
return function() { return function() {
var args = Array.prototype.slice.call(arguments, 0); var args = Array.prototype.slice.call(arguments, 0);
+5
View File
@@ -4,8 +4,13 @@ var Immutable = require('immutable');
* Reduce the difference between a map and its default version * Reduce the difference between a map and its default version
* @param {Map} defaultVersion * @param {Map} defaultVersion
* @param {Map} currentVersion * @param {Map} currentVersion
* @return {Map} The properties of currentVersion that differs from defaultVersion
*/ */
function reducedObject(defaultVersion, currentVersion) { function reducedObject(defaultVersion, currentVersion) {
if(defaultVersion === undefined) {
return currentVersion;
}
return currentVersion.reduce(function(result, value, key) { return currentVersion.reduce(function(result, value, key) {
var defaultValue = defaultVersion.get(key); var defaultValue = defaultVersion.get(key);
+5 -4
View File
@@ -1,6 +1,6 @@
{ {
"name": "gitbook", "name": "gitbook",
"version": "3.1.1", "version": "3.2.2",
"homepage": "https://www.gitbook.com", "homepage": "https://www.gitbook.com",
"description": "Library and cmd utility to generate GitBooks", "description": "Library and cmd utility to generate GitBooks",
"main": "lib/index.js", "main": "lib/index.js",
@@ -26,10 +26,10 @@
"gitbook-plugin-fontsettings": "2.0.0", "gitbook-plugin-fontsettings": "2.0.0",
"gitbook-plugin-highlight": "2.0.2", "gitbook-plugin-highlight": "2.0.2",
"gitbook-plugin-livereload": "0.0.1", "gitbook-plugin-livereload": "0.0.1",
"gitbook-plugin-lunr": "1.1.0", "gitbook-plugin-lunr": "1.2.0",
"gitbook-plugin-search": "2.2.1", "gitbook-plugin-search": "2.2.1",
"gitbook-plugin-sharing": "1.0.2", "gitbook-plugin-sharing": "1.0.2",
"gitbook-plugin-theme-default": "1.0.4", "gitbook-plugin-theme-default": "1.0.6",
"github-slugid": "1.0.1", "github-slugid": "1.0.1",
"graceful-fs": "4.1.4", "graceful-fs": "4.1.4",
"i18n-t": "1.0.1", "i18n-t": "1.0.1",
@@ -44,10 +44,11 @@
"moment": "2.13.0", "moment": "2.13.0",
"npm": "3.9.2", "npm": "3.9.2",
"npmi": "2.0.1", "npmi": "2.0.1",
"nunjucks": "2.4.2", "nunjucks": "2.5.2",
"nunjucks-do": "1.0.0", "nunjucks-do": "1.0.0",
"object-path": "^0.9.2", "object-path": "^0.9.2",
"omit-keys": "^0.1.0", "omit-keys": "^0.1.0",
"open": "0.0.5",
"q": "1.4.1", "q": "1.4.1",
"read-installed": "^4.0.3", "read-installed": "^4.0.3",
"request": "2.72.0", "request": "2.72.0",