Compare commits

...

93 Commits

Author SHA1 Message Date
Samy Pesse f998e2dec9 Bump version to 2.0.4 2015-05-28 18:07:20 +02:00
Samy Pesse 2c0bd53a91 Fix i18n used in multilingual book 2015-05-28 17:06:09 +02:00
Samy Pesse 6dd7f6162f Add title to languages chooser
Related to #757
2015-05-28 16:14:03 +02:00
Samy Pesse 475b0bb2b3 Adapt to nunjucks 1.3.x 2015-05-28 15:59:14 +02:00
Samy Pesse e6343935e3 Update nunjucks to fix raw tags 2015-05-28 15:50:46 +02:00
Samy Pessé 946883fd4c Merge pull request #772 from GitbookIO/feature/glossary_order
Fix #768: sort glossary, start with longest matchs
2015-05-28 15:21:03 +02:00
Samy Pessé b1b7e3148b Merge pull request #743 from chudaol/master
Added vk sharing button.
2015-05-28 14:54:03 +02:00
Samy Pesse 32203f6438 Sort glossary before applying it on pages 2015-05-28 14:49:53 +02:00
Samy Pesse f2d3c5d2ed Add test for #768 2015-05-28 14:38:21 +02:00
Samy Pessé 7e2f0ed4bc Merge pull request #758 from aschempp/hotfix/x-ua-compatible
Fix the X-UA-Compatible meta tag
2015-05-28 14:18:19 +02:00
Samy Pessé a877acf905 Merge pull request #759 from aschempp/hotfix/stylesheets
Move style sheets to the <head> section
2015-05-28 14:17:39 +02:00
Samy Pesse ac756ddf7e Bump version to 2.0.3 2015-05-27 21:11:58 +02:00
Samy Pesse 36e2236e6b Fix #765: in init handle correctly empty entries
Add tests for it, fix #769
2015-05-27 21:05:36 +02:00
Samy Pesse 72df665520 Update gitbook-parsers@0.7.5 2015-05-27 19:11:50 +02:00
Samy Pessé 07785528a5 Merge pull request #767 from wilhelmmatilainen/patch-1
Don't create panic by telling about false overwrite
2015-05-27 13:17:05 +02:00
Wilhelm bb579dd581 Don't create panic by telling about false overwrite 2015-05-27 14:13:02 +03:00
Samy Pessé a7d3064340 Change license to valid SPDX code 2015-05-26 16:10:11 +02:00
Andreas Schempp 1a60778248 Move style sheets to the <head> section
see https://github.com/GitbookIO/gitbook/issues/756
2015-05-23 09:14:26 +02:00
Andreas Schempp cda4bb5bda Fix the X-UA-Compatible meta tag
see https://github.com/GitbookIO/gitbook/issues/755
2015-05-23 09:06:58 +02:00
Olga Filipova 7543781046 Added vk sharing button. 2015-05-12 22:30:09 +02:00
Samy Pessé 82f3ffad06 Merge pull request #730 from creynders/patch-1
Fix typo in warning in `lib/plugin`
2015-05-04 14:47:56 +02:00
creynders dc4d2a1731 Fix typo in warning in lib/plugin 2015-05-04 13:16:47 +02:00
Samy Pessé 2523925915 Bump version to 2.0.2 2015-05-02 12:39:05 +02:00
Samy Pesse d5bbd8475c Fix #721: use links.join instead of path.join for links in page 2015-04-23 12:58:24 -05:00
Samy Pesse 54d195268a Add test relative links (related to #721) 2015-04-23 12:05:04 -05:00
Samy Pesse a0deb9509f Merge branch 'awrelll-master' 2015-04-20 07:53:16 -05:00
Samy Pesse b0b1433594 Fix authors list merge 2015-04-20 07:52:12 -05:00
Samy Pessé 17a2c0a37c Merge pull request #706 from savikko/patch-1
Added Finnish author
2015-04-14 18:56:31 -05:00
Samy Pessé fd68ea1cc2 Merge pull request #705 from savikko/master
Added Finnish
2015-04-14 18:56:21 -05:00
Tommi Savikko 784874c776 Added Finnish author 2015-04-14 22:39:23 +03:00
Thomas Clayton f45c6d3466 Added Finnish 2015-04-14 21:50:46 +03:00
Samy Pessé 98af70902f Merge pull request #701 from anthonyfok/patch-1
Fix typo in lib/book.js: lanuages → languages
2015-04-10 20:50:35 -05:00
Anthony Fok 41a67b5c4c Fix typo in lib/book.js: lanuages → languages 2015-04-10 07:41:12 -06:00
Samy Pessé 83ee903af4 Merge pull request #700 from paulmillr/master
Switch from gaze to chokidar.
2015-04-10 10:39:13 +02:00
Samy Pessé e591b0e485 Merge pull request #696 from sindresorhus/escaperegex-module
use the `escape-string-regexp` module
2015-04-10 10:37:53 +02:00
Paul Miller bcc9a34742 Switch from gaze to chokidar. 2015-04-10 06:09:04 +03:00
Sindre Sorhus 6b56c7de7f use the escape-string-regexp module
no point in hardcoding this.

https://github.com/sindresorhus/escape-string-regexp
2015-04-08 18:24:26 +07:00
Iancu Aurel 7b42719699 korean and japanese added 2015-04-07 17:34:40 +03:00
awrelll 64b8343f67 korean support added 2015-04-07 17:32:33 +03:00
awrelll fcc5089fa6 japan support added 2015-04-07 17:26:45 +03:00
Samy Pessé 334f782aa8 Merge pull request #693 from awrelll/patch-1
Romanian author added
2015-04-07 16:21:56 +02:00
Samy Pessé 1776f2bf77 Merge pull request #691 from awrelll/master
support for romanian language
2015-04-07 16:21:34 +02:00
Iancu Aurel e259412f79 Romanian author added 2015-04-07 17:21:05 +03:00
awrelll 999a02f110 support for romanian language 2015-04-07 17:12:41 +03:00
Samy Pessé 604d0fba65 Update nunjucks@1.3.0 2015-04-03 22:31:55 +02:00
Samy Pessé 0e8f7b870b Bump version to 2.0.1 2015-04-02 19:41:14 +02:00
Samy Pessé 1eebc9a46e Normalize structure parsing error 2015-04-02 19:21:39 +02:00
Samy Pessé 0a94c80c44 Normalize template errors 2015-04-02 18:59:56 +02:00
Samy Pessé c70bb2fbd8 Update gitbook-parsers@0.7.4 2015-04-02 18:31:49 +02:00
Samy Pessé 12c06b384f Don't fail if config doesn't exists 2015-04-02 09:43:48 +02:00
Samy Pessé 82a58e7ac3 Invalidate configuration cache when reloading 2015-04-02 09:38:57 +02:00
Samy Pessé dcb56ef433 Merge pull request #683 from GitbookIO/fix/i18n
Fix i18n in json format
2015-04-01 22:23:23 +02:00
Samy Pessé 8da91de514 Don't update translations 2015-04-01 22:21:13 +02:00
Samy Pessé 4b20685562 Use i18n node module for template translation 2015-04-01 22:17:12 +02:00
Samy Pessé fff7c5cc3a Add back support for options.originalInput
Related to rtCamp/gitbook-plugin-edit-link#2
2015-03-30 16:50:26 +02:00
Samy Pessé 3065742b73 Separate book.contentLink and book.contentPath 2015-03-28 15:54:34 +01:00
Samy Pessé ffd69ad1f2 Add test for summary paths
Related to #674
2015-03-28 15:28:28 +01:00
Samy Pessé 9004011479 Merge pull request #673 from lszeremeta/master
Polish (pl) added in theme/i18n
2015-03-28 14:54:50 +01:00
Łukasz Szeremeta 1046bb4133 Add @lszeremeta to translators 2015-03-28 14:48:16 +01:00
Łukasz Szeremeta 5578505213 Polish (pl) added in theme/i18n 2015-03-27 22:03:28 +01:00
Samy Pessé a61f56662a Bump version to 2.0.0 2015-03-25 10:43:58 +01:00
Samy Pessé f42e48be03 Fix scroll reset on small resolutions (mobile & tablet) 2015-03-24 23:59:03 +01:00
Samy Pessé f640e101ba Fix scroling position when preparing page 2015-03-24 23:52:41 +01:00
Samy Pessé b7da276ae0 Fix title for introduction (with i18n) 2015-03-24 23:49:12 +01:00
Samy Pessé bf7c0989f5 Update gitbook-parsers@0.7.2 2015-03-24 23:35:17 +01:00
Samy Pessé 65fdbe7f55 Simplify examples of commands 2015-03-24 23:19:00 +01:00
Samy Pessé c9af209a93 Merge pull request #667 from GitbookIO/better-testing
Better Unit Tests
2015-03-24 23:14:17 +01:00
Samy Pessé 48ab44a776 Add tests for conrefs 2015-03-24 18:22:44 +01:00
Samy Pessé b2e684af8f Add test for templating context 2015-03-24 17:34:47 +01:00
Samy Pessé b38a2c11a4 Add tests for plugins 2015-03-24 17:31:15 +01:00
Samy Pessé c31acef47a Add tests for images in ebook 2015-03-24 16:26:19 +01:00
Samy Pessé e9a573e18a Add test for default description from readme 2015-03-24 14:57:29 +01:00
Samy Pessé c07ddc77f7 Add tests for links 2015-03-24 14:52:24 +01:00
Samy Pessé 303fc992d4 Add test for git url parsing 2015-03-24 14:44:07 +01:00
Samy Pessé 4b7797f61b Add basic tests for multilingual books 2015-03-24 14:16:03 +01:00
Samy Pessé f775d41933 Add base tests for ebook generation 2015-03-24 13:52:29 +01:00
Samy Pessé 7722e7bdfa Update gitbook-parsers@0.7.1 2015-03-24 13:33:56 +01:00
Samy Pessé 346c05f0de Add tests for configuration parsing 2015-03-24 13:24:20 +01:00
Samy Pessé 73c69923b3 Add test for summary parsing
Update gitbook-parsers
2015-03-24 13:11:29 +01:00
Samy Pessé afbca4bdf5 Improve tests for glossary 2015-03-24 11:54:03 +01:00
Samy Pessé b61371942b Add test for glossary replacements 2015-03-24 11:27:37 +01:00
Samy Pessé 61c07e8876 Add test for glossary parsing 2015-03-24 10:24:49 +01:00
Samy Pessé d317741144 Add basic test for multilingual book 2015-03-24 09:36:51 +01:00
Samy Pessé 275739a778 Add basic test for website generation 2015-03-24 08:49:39 +01:00
Samy Pessé cb3a43ed8a Add string representation for books 2015-03-24 08:49:22 +01:00
Samy Pessé ec8d1d8fc9 Improve test for json format 2015-03-23 23:48:46 +01:00
Samy Pessé 868a3186dd Add assertion to test that a file exists 2015-03-23 23:32:07 +01:00
Samy Pessé 17b546181c Fix cleanup after tests 2015-03-23 23:23:25 +01:00
Samy Pessé 2d1aa15af8 New cleaner helper for testing 2015-03-23 23:18:15 +01:00
Samy Pessé 63ee94ff89 Ignore codeblocks when replacing glossary terms 2015-03-23 11:00:50 +01:00
Samy Pessé 7d9dc08a38 Highlight codeblocks in gitbook instead than the parsers 2015-03-23 10:31:48 +01:00
Samy Pessé a836bdedb4 Bump version to 2.0.0-beta.5 2015-03-17 11:23:35 +01:00
Samy Pessé 15ebae8cb1 Fix #641: fix progress order in json format 2015-03-17 11:22:56 +01:00
124 changed files with 1399 additions and 740 deletions
+10
View File
@@ -30,6 +30,8 @@ Translators
- Knut Melvær (@kmelve)
- Persian (Farsi)
- Mohammad Hossein Mojtahedi (@mhm5000)
- Polish
- Łukasz Szeremeta (@lszeremeta)
- Portuguese
- Ryan O'Mullan (@RyanOM)
- Spanish
@@ -40,3 +42,11 @@ Translators
- Hu Hao (@howiehu)
- French
- Samy Pessé (@SamyPesse)
- Romanian
- Iancu Aurel (@awrelll)
- Finnish
- Tommi Savikko (@savikko)
- Japanese
- Iancu Aurel (@awrelll)
- Korean
- Iancu Aurel (@awrelll)
+36
View File
@@ -2,6 +2,42 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 2.0.4
- Fix `{% raw %}`, got confused with "fake" variable declarations
- Fix title of language chooser
- Fix the X-UA-Compatible meta tag
- Move style sheets to the <head> section
## 2.0.3
- Fix `gitbook init` for SUMMARY with empty entries
- Fix escaping of code blocks in markdown
## 2.0.2
- Fix relative links in windows
- Improve watcher in serve command (switch to chokidar)
- Add Romanian translation (`ro`)
- Add Finish translation (`fi`)
- Add Japanese translation (`jp`)
- Add Korean translation (`kr`)
## 2.0.1
- Improve error logging (display file, line and column)
- Add back support for `options.originalInput`
- Don't process math in markdown parser (delegated to `mathjax` plugin)
- Fix some cases of code blocks escaping
- Fix i18n for introduction title in json format
- Fix reload when book configuration is updated
- Fix backslashes in url when building on windows
## 2.0.0
- Fix page title of introduction
- Ignore codeblocks when replacing glossary terms
- Improve Unit Tests
- Fix scrolling position in website when preparing page
## 2.0.0-beta.5
- Fix progress order in json format
## 2.0.0-beta.4
- Fix default generator for use programmatically
- Add option "author" for html meta tags
+2 -2
View File
@@ -32,13 +32,13 @@ $ gitbook init
You can serve a repository as a book using:
```
$ gitbook serve ./repository
$ gitbook serve
```
Or simply build the static website using:
```
$ gitbook build ./repository ./outputFolder
$ gitbook build
```
## Features
+96 -22
View File
@@ -2,9 +2,9 @@ var Q = require("q");
var _ = require("lodash");
var path = require("path");
var util = require("util");
var lunr = require('lunr');
var lunr = require("lunr");
var parsers = require("gitbook-parsers");
var color = require('bash-color');
var color = require("bash-color");
var fs = require("./utils/fs");
var parseNavigation = require("./utils/navigation");
@@ -12,6 +12,7 @@ var parseProgress = require("./utils/progress");
var pageUtil = require("./utils/page");
var batch = require("./utils/batch");
var links = require("./utils/links");
var i18n = require("./utils/i18n");
var logger = require("./utils/logger");
var Configuration = require("./configuration");
@@ -94,6 +95,11 @@ var Book = function(root, context, parent) {
_.bindAll(this);
};
// Return string representation
Book.prototype.toString = function() {
return "[Book "+this.root+"]";
};
// Initialize and parse the book: config, summary, glossary
Book.prototype.parse = function() {
var that = this;
@@ -109,7 +115,7 @@ Book.prototype.parse = function() {
return that.parseLangs()
.then(function() {
multilingual = that.langs.length > 0;
if (multilingual) that.log.info.ln("Parsing multilingual book, with", that.langs.length, "lanuages");
if (multilingual) that.log.info.ln("Parsing multilingual book, with", that.langs.length, "languages");
// Sub-books that inherit from the current book configuration
that.books = _.map(that.langs, function(lang) {
@@ -229,8 +235,15 @@ Book.prototype.generate = function(generator) {
return _.reduce(ops["content"] || [], function(prev, file, i) {
return prev.then(function() {
var p = ((i*100)/nFiles).toFixed(0)+"%";
that.log.info.ln("processing", file, p);
return Q(generator.convertFile(file));
that.log.debug.ln("processing", file, p);
return Q(generator.convertFile(file))
.fail(function(err) {
// Transform error message to signal file
throw that.normError(err, {
fileName: file
});
});
});
}, Q());
});
@@ -364,7 +377,13 @@ Book.prototype.parseReadme = function() {
that.log.debug.ln("readme located at", that.readmeFile);
return that.template.renderFile(that.readmeFile)
.then(function(content) {
return readme.parser.readme(content);
return readme.parser.readme(content)
.fail(function(err) {
throw that.normError(err, {
name: err.name || "Readme Parse Error",
fileName: that.readmeFile
});
});
});
})
.then(function(readme) {
@@ -391,7 +410,13 @@ Book.prototype.parseLangs = function() {
that.log.debug.ln("languages index located at", that.langsFile);
return that.template.renderFile(that.langsFile)
.then(function(content) {
return langs.parser.langs(content);
return langs.parser.langs(content)
.fail(function(err) {
throw that.normError(err, {
name: err.name || "Langs Parse Error",
fileName: that.langsFile
});
});
});
})
.then(function(langs) {
@@ -420,8 +445,14 @@ Book.prototype.parseSummary = function() {
.then(function(content) {
return summary.parser.summary(content, {
entryPoint: that.readmeFile,
entryPointTitle: "",
entryPointTitle: that.i18n('SUMMARY_INTRODUCTION'),
files: that.files
})
.fail(function(err) {
throw that.normError(err, {
name: err.name || "Summary Parse Error",
fileName: that.summaryFile
});
});
});
})
@@ -450,7 +481,13 @@ Book.prototype.parseGlossary = function() {
that.log.debug.ln("glossary located at", that.glossaryFile);
return that.template.renderFile(that.glossaryFile)
.then(function(content) {
return glossary.parser.glossary(content);
return glossary.parser.glossary(content)
.fail(function(err) {
throw that.normError(err, {
name: err.name || "Glossary Parse Error",
fileName: that.glossaryFile
});
});
});
})
.then(function(glossary) {
@@ -670,8 +707,8 @@ Book.prototype.resolve = function(p) {
return path.resolve(this.root, p);
};
// Normalize a link to .html and convert README -> index
Book.prototype.contentLink = function(link) {
// Normalize a path to .html and convert README -> index
Book.prototype.contentPath = function(link) {
if (
path.basename(link, path.extname(link)) == "README"
|| link == this.readmeFile
@@ -683,6 +720,11 @@ Book.prototype.contentLink = function(link) {
return link;
}
// Normalize a link to .html and convert README -> index
Book.prototype.contentLink = function(link) {
return links.normalize(this.contentPath(link));
}
// Index a page into the search index
Book.prototype.indexPage = function(page) {
var nav = this.navigation[page.path];
@@ -717,22 +759,49 @@ Book.prototype.setOutput = function(p) {
});
};
// Translate a strign according to the book language
Book.prototype.i18n = function(phrase) {
var args = Array.prototype.slice.call(arguments);
return i18n.__.apply({}, [this.config.normalizeLanguage()].concat(args));
};
// Normalize error
Book.prototype.normError = function(err, opts, defs) {
if (_.isString(err)) err = new Error(err);
// Extend err
_.extend(err, opts || {});
_.defaults(err, defs || {});
err.lineNumber = err.lineNumber || err.lineno;
err.columnNumber = err.columnNumber || err.colno;
err.toString = function() {
var attributes = [];
if (this.fileName) attributes.push("In file '"+this.fileName+"'");
if (this.lineNumber) attributes.push("Line "+this.lineNumber);
if (this.columnNumber) attributes.push("Column "+this.columnNumber);
return (this.name || "Error")+": "+this.message+((attributes.length > 0)? " ("+attributes.join(", ")+")" : "")
};
return err;
};
// Init and return a book
Book.init = function(root) {
var book = new Book(root);
Book.init = function(root, opts) {
var book = new Book(root, opts);
var extensionToUse = ".md";
var chaptersPaths = function(chapters) {
return _.reduce(chapters || [], function(accu, chapter) {
if (!chapter.path) return accu;
var o = {
title: chapter.title
};
if (chapter.path) o.path = chapter.path;
return accu.concat(
_.filter([
{
title: chapter.title,
path: chapter.path
}
].concat(chaptersPaths(chapter.articles)))
[o].concat(chaptersPaths(chapter.articles))
);
}, []);
};
@@ -769,12 +838,17 @@ Book.init = function(root) {
.then(function(chapters) {
// Create files that don't exist
return Q.all(_.map(chapters, function(chapter) {
if (!chapter.path) return Q();
var absolutePath = path.resolve(book.root, chapter.path);
return fs.exists(absolutePath)
.then(function(exists) {
book.log.info.ln("create", chapter.path);
if(exists) return;
if(exists) {
book.log.info.ln("found", chapter.path);
return;
} else {
book.log.info.ln("create", chapter.path);
}
return fs.mkdirp(path.dirname(absolutePath))
.then(function() {
+25 -3
View File
@@ -60,7 +60,6 @@ function normalizePluginsNames(plugins) {
return _.pluck(normalizePluginsList(plugins), "name");
};
var Configuration = function(book, options) {
var that = this;
@@ -75,6 +74,20 @@ var Configuration = function(book, options) {
return that.book.root;
}
});
// options.originalInput == book.parent.root
Object.defineProperty(this.options, "originalInput", {
get: function () {
return that.book.parent? that.book.parent.root : undefined;
}
});
// options.originalOutput == book.parent.options.output
Object.defineProperty(this.options, "originalOutput", {
get: function () {
return that.book.parent? that.book.parent.options.output : undefined;
}
});
};
// Read and parse the configuration
@@ -83,8 +96,17 @@ Configuration.prototype.load = function() {
return Q()
.then(function() {
var configPath, config;
try {
var _config = require(path.resolve(that.book.root, that.options.configFile));
configPath = require.resolve(
path.resolve(that.book.root, that.options.configFile)
);
// Invalidate node.js cache for livreloading
delete require.cache[configPath];
_config = require(configPath);
that.options = _.merge(
that.options,
_.omit(_config, 'configFile', 'defaultsPlugins', 'generator', 'extension')
@@ -111,7 +133,7 @@ Configuration.prototype.load = function() {
// Default value for text direction (from language)
if (!that.options.direction) {
var lang = i18n.getByLanguage(that.options.language);
var lang = i18n.getCatalog(that.options.language);
if (lang) that.options.direction = lang.direction;
}
+7 -11
View File
@@ -4,9 +4,8 @@ var Q = require("q");
var _ = require("lodash");
var nunjucks = require("nunjucks");
var AutoEscapeExtension = require("nunjucks-autoescape");
var FilterExtension = require("nunjucks-filter");
var I18nExtension = require("nunjucks-i18n");
var AutoEscapeExtension = require("nunjucks-autoescape")(nunjucks);
var FilterExtension = require("nunjucks-filter")(nunjucks);
var fs = require("../utils/fs");
var BaseGenerator = require("../generator");
@@ -79,8 +78,8 @@ Generator.prototype.prepareTemplateEngine = function() {
.then(function() {
var language = that.book.config.normalizeLanguage();
if (!i18n.getByLanguage(language) && language != "en") {
that.book.log.warn.ln("Language '"+language+"' is not available as a layout locales (en, "+i18n.getLanguages().join(", ")+")");
if (!i18n.hasLocale(language)) {
that.book.log.warn.ln("Language '"+language+"' is not available as a layout locales (en, "+i18n.getLocales().join(", ")+")");
}
var folders = _.chain(that.templates)
@@ -105,11 +104,6 @@ Generator.prototype.prepareTemplateEngine = function() {
// Add extension
that.env.addExtension('AutoEscapeExtension', new AutoEscapeExtension(that.env));
that.env.addExtension('FilterExtension', new FilterExtension(that.env));
that.env.addExtension('I18nExtension', new I18nExtension({
env: that.env,
translations: i18n.getLocales(),
locale: "language"
}));
});
};
@@ -136,7 +130,7 @@ Generator.prototype.convertFile = function(input) {
}
})
.then(function(page) {
var relativeOutput = that.book.contentLink(page.path);
var relativeOutput = that.book.contentPath(page.path);
var output = path.join(that.options.output, relativeOutput);
var basePath = path.relative(path.dirname(output), that.options.output) || ".";
@@ -243,6 +237,8 @@ Generator.prototype._writeTemplate = function(tpl, options, output, interpolate)
basePath: ".",
staticBase: path.join(".", "gitbook"),
'__': that.book.i18n.bind(that.book)
}, options)
);
})
+1 -1
View File
@@ -155,7 +155,7 @@ Plugin.prototype.callHook = function(name, data) {
if (!hookFunc) return Q(data);
this.book.log.debug.ln("call hook", name);
if (!_.contains(Plugin.HOOKS, name)) this.book.log.warn.ln("hook '"+name+"' used by plugin '"+this.name+"' is deprecated, and will be remove in the coming versions");
if (!_.contains(Plugin.HOOKS, name)) this.book.log.warn.ln("hook '"+name+"' used by plugin '"+this.name+"' is deprecated, and will be removed in the coming versions");
return Q()
.then(function() {
+9 -3
View File
@@ -2,9 +2,9 @@ var _ = require("lodash");
var Q = require("q");
var path = require("path");
var nunjucks = require("nunjucks");
var escapeStringRegexp = require("escape-string-regexp");
var git = require("./utils/git");
var stringUtils = require("./utils/string");
var fs = require("./utils/fs");
var batch = require("./utils/batch");
var pkg = require("../package.json");
@@ -302,7 +302,7 @@ TemplateEngine.prototype.addBlock = function(name, block) {
TemplateEngine.prototype._applyShortcut = function(parser, content, shortcut) {
if (!_.contains(shortcut.parsers, parser)) return content;
var regex = new RegExp(
stringUtils.escapeRegex(shortcut.start) + "([\\s\\S]*?[^\\$])" + stringUtils.escapeRegex(shortcut.end),
escapeStringRegexp(shortcut.start) + "([\\s\\S]*?[^\\$])" + escapeStringRegexp(shortcut.end),
'g'
);
return content.replace(regex, function(all, match) {
@@ -331,7 +331,13 @@ TemplateEngine.prototype.renderString = function(content, context, options) {
// Replace shortcuts
content = _.reduce(this.shortcuts, _.partial(this._applyShortcut.bind(this), options.type), content);
return Q.nfcall(this.env.renderString.bind(this.env), content, context, options);
return Q.nfcall(this.env.renderString.bind(this.env), content, context, options)
.fail(function(err) {
if (_.isString(err)) err = new Error(err);
err.message = err.message.replace(/^Error: /, "");
throw err;
});
};
// Render a file from the book
+36
View File
@@ -0,0 +1,36 @@
var hljs = require('highlight.js');
var MAP = {
'py': 'python',
'js': 'javascript',
'json': 'javascript',
'rb': 'ruby',
'csharp': 'cs',
};
function normalize(lang) {
if(!lang) { return null; }
var lower = lang.toLowerCase();
return MAP[lower] || lower;
}
function highlight(lang, code) {
if(!lang) return code;
// Normalize lang
lang = normalize(lang);
try {
return hljs.highlight(lang, code).value;
} catch(e) { }
return code;
}
// Exports
module.exports = {
highlight: highlight,
normalize: normalize,
MAP: MAP
};
+40 -32
View File
@@ -2,32 +2,20 @@ var _ = require("lodash");
var path = require("path");
var fs = require("fs");
var I18N_PATH = path.resolve(__dirname, "../../theme/i18n/")
var i18n = require("i18n");
var getLocales = _.memoize(function() {
var locales = fs.readdirSync(I18N_PATH);
return _.chain(locales)
.map(function(local) {
local = path.basename(local, ".json");
return [local, _.extend({
direction: "ltr"
}, require(path.join(I18N_PATH, local)), {
id: local
})];
})
.object()
.value();
var I18N_PATH = path.resolve(__dirname, "../../theme/i18n/")
var DEFAULT_LANGUAGE = "en";
var LOCALES = _.map(fs.readdirSync(I18N_PATH), function(lang) {
return path.basename(lang, ".json");
});
var getLanguages = function() {
return _.keys(getLocales());
};
var getByLanguage = function(lang) {
lang = normalizeLanguage(lang);
var locales = getLocales();
return locales[lang];
};
i18n.configure({
locales: LOCALES,
directory: I18N_PATH,
defaultLocale: DEFAULT_LANGUAGE,
updateFiles: false
});
var compareLocales = function(lang, locale) {
var langMain = _.first(lang.split("-"));
@@ -43,12 +31,9 @@ var compareLocales = function(lang, locale) {
};
var normalizeLanguage = _.memoize(function(lang) {
var locales = getLocales();
var language = _.chain(locales)
var language = _.chain(LOCALES)
.values()
.map(function(locale) {
locale = locale.id;
return {
locale: locale,
score: compareLocales(lang, locale)
@@ -64,9 +49,32 @@ var normalizeLanguage = _.memoize(function(lang) {
return language || lang;
});
module.exports = {
getLocales: getLocales,
getLanguages: getLanguages,
getByLanguage: getByLanguage,
normalizeLanguage: normalizeLanguage
var translate = function(locale, phrase) {
var args = Array.prototype.slice.call(arguments, 2);
return i18n.__.apply({}, [{
locale: locale,
phrase: phrase
}].concat(args));
};
var getCatalog = function(locale) {
locale = normalizeLanguage(locale);
return i18n.getCatalog(locale);
};
var getLocales = function() {
return LOCALES;
};
var hasLocale = function(locale) {
return _.contains(LOCALES, locale);
}
module.exports = {
__: translate,
normalizeLanguage: normalizeLanguage,
getCatalog: getCatalog,
getLocales: getLocales,
hasLocale: hasLocale
};
+3 -1
View File
@@ -36,7 +36,7 @@ function navigation(summary, files) {
var prev = null, next = null;
// Skip if no path
if(!current.path) return null;
if(!current.exists) return null;
// Find prev
prev = _.chain(navNodes)
@@ -57,7 +57,9 @@ function navigation(summary, files) {
return [current.path, {
index: i,
title: current.title,
introduction: current.introduction,
prev: prev,
next: next,
level: current.level,
+35 -3
View File
@@ -11,6 +11,7 @@ var links = require('./links');
var imgUtils = require('./images');
var fs = require('./fs');
var batch = require('./batch');
var code = require('./code');
// Render a cheerio dom as html
var renderDom = function($, dom, options) {
@@ -183,6 +184,7 @@ function normalizeHtml(src, options) {
$(this).attr("src", src);
});
// Normalize links
$("a").each(function() {
var href = $(this).attr("href");
if (!href) return;
@@ -191,7 +193,7 @@ function normalizeHtml(src, options) {
// Keep it as it is
} else if (links.isRelative(href)) {
var parts = url.parse(href);
var absolutePath = path.join(options.base, parts.pathname);
var absolutePath = links.join(options.base, parts.pathname);
var anchor = parts.hash || "";
// If is in navigation relative: transform as content
@@ -210,12 +212,42 @@ function normalizeHtml(src, options) {
$(this).attr("href", href);
});
// Replace glossayr terms
_.each(options.glossary, function(term) {
// Highlight code blocks
$("code").each(function() {
// Extract language
var lang = _.chain(
($(this).attr("class") || "").split(" ")
)
.map(function(cl) {
if (cl.search("lang-") === 0) return cl.slice("lang-".length);
return null;
})
.compact()
.first()
.value();
if (lang) {
var html = code.highlight(
lang,
$(this).text()
);
$(this).html(html);
}
});
// Replace glossary terms
var glossary = _.sortBy(options.glossary, function(term) {
return -term.name.length;
});
_.each(glossary, function(term) {
var r = new RegExp( "\\b(" + pregQuote(term.name.toLowerCase()) + ")\\b" , 'gi' );
var includedInFiles = false;
$("*").each(function() {
// Ignore codeblocks
if (_.contains(["code", "pre", "a"], this.name.toLowerCase())) return;
replaceText($, this, r, function(match) {
// Add to files index in glossary
if (!includedInFiles) {
+8
View File
@@ -7,10 +7,18 @@ var calculProgress = function(navigation, current) {
var done = true;
var chapters = _.chain(navigation)
// Transform as array
.map(function(nav, path) {
nav.path = path;
return nav;
})
// Sort entries
.sortBy(function(nav) {
return nav.index;
})
.map(function(nav, i) {
// Calcul percent
nav.percent = (i * 100) / Math.max((n - 1), 1);
-5
View File
@@ -20,12 +20,7 @@ function optionsToShellArgs(options) {
.join(" ");
}
function escapeRegex(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
module.exports = {
escapeRegex: escapeRegex,
escapeShellArg: escapeShellArg,
optionsToShellArgs: optionsToShellArgs,
toLowerCase: String.prototype.toLowerCase.call.bind(String.prototype.toLowerCase)
+8 -7
View File
@@ -1,7 +1,7 @@
var Q = require('q');
var _ = require('lodash');
var path = require('path');
var Gaze = require('gaze').Gaze;
var chokidar = require('chokidar');
var parsers = require('gitbook-parsers')
@@ -17,17 +17,18 @@ function watch(dir) {
toWatch.push("**/*"+ext);
});
var gaze = new Gaze(toWatch, {
cwd: dir
var watcher = chokidar.watch(toWatch, {
cwd: dir,
ignoreInitial: true
});
gaze.once("all", function(e, filepath) {
gaze.close();
watcher.once("all", function(e, filepath) {
watcher.close();
d.resolve(filepath);
});
gaze.once("error", function(err) {
gaze.close();
watcher.once("error", function(err) {
watcher.close();
d.reject(err);
});
+14 -11
View File
@@ -1,6 +1,6 @@
{
"name": "gitbook",
"version": "2.0.0-beta.4",
"version": "2.0.4",
"homepage": "https://www.gitbook.com",
"description": "Library and cmd utility to generate GitBooks",
"main": "lib/index.js",
@@ -12,16 +12,16 @@
"resolve": "0.6.3",
"fs-extra": "0.16.5",
"fstream-ignore": "1.0.2",
"gitbook-parsers": "0.5.4",
"nunjucks": "git+https://github.com/mozilla/nunjucks.git#0f8b21b8df7e8e852b2e1889388653b7075f0d09",
"nunjucks-autoescape": "0.1.1",
"nunjucks-filter": "0.1.0",
"nunjucks-i18n": "1.0.0",
"gitbook-parsers": "0.7.5",
"nunjucks": "mozilla/nunjucks#103513c294835bcbe64222de6db494e2555e294e",
"nunjucks-autoescape": "1.0.0",
"nunjucks-filter": "1.0.0",
"i18n": "0.5.0",
"semver": "2.2.1",
"npmi": "0.1.1",
"cheerio": "0.18.0",
"cheerio": "0.19.0",
"gitbook-plugin-livereload": "0.0.1",
"gaze": "~0.5.1",
"chokidar": "~1.0.1",
"send": "0.2.0",
"tiny-lr": "0.1.5",
"tmp": "0.0.24",
@@ -31,10 +31,13 @@
"request": "2.51.0",
"npm": "2.4.1",
"dom-serializer": "0.1.0",
"spawn-cmd": "0.0.2"
"spawn-cmd": "0.0.2",
"highlight.js": "8.4.0",
"escape-string-regexp": "1.0.3"
},
"devDependencies": {
"mocha": "2.2.1",
"should": "5.2.0",
"grunt": "~0.4.2",
"grunt-cli": "0.1.11",
"grunt-contrib-copy": "0.5.0",
@@ -43,7 +46,7 @@
"grunt-bower-install-simple": "0.9.2"
},
"scripts": {
"test": "node_modules/.bin/mocha --reporter list --timeout 15000"
"test": "node_modules/.bin/mocha --reporter spec --timeout 15000"
},
"repository": {
"type": "git",
@@ -58,7 +61,7 @@
"gitbook"
],
"author": "FriendCode Inc. <contact@gitbook.com>",
"license": "Apache 2",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/GitbookIO/gitbook/issues"
},
+54
View File
@@ -0,0 +1,54 @@
var _ = require('lodash');
var fs = require('fs');
var path = require('path');
var should = require('should');
var cheerio = require('cheerio');
should.Assertion.add('file', function(file, description) {
this.params = { actual: this.obj.toString(), operator: 'have file ' + file, message: description };
this.obj.should.have.property('options').which.is.an.Object;
this.obj.options.should.have.property('output').which.is.a.String;
this.assert(fs.existsSync(path.resolve(this.obj.options.output, file)));
});
should.Assertion.add('jsonfile', function(file, description) {
this.params = { actual: this.obj.toString(), operator: 'have valid jsonfile ' + file, message: description };
this.obj.should.have.property('options').which.is.an.Object;
this.obj.options.should.have.property('output').which.is.a.String;
this.assert(JSON.parse(fs.readFileSync(path.resolve(this.obj.options.output, file), { encoding: "utf-8" })));
});
should.Assertion.add('html', function(rules, description) {
this.params = { actual: "HTML string", operator: 'valid html', message: description };
var $ = cheerio.load(this.obj);
_.each(rules, function(validations, query) {
validations = _.defaults(validations || {}, {
count: 1,
attributes: {},
trim: false,
text: undefined
});
var $el = $(query);
// Test number of elements
$el.should.have.lengthOf(validations.count);
// Test text
if (validations.text !== undefined) {
var text = $el.text();
if (validations.trim) text = text.trim();
text.should.be.equal(validations.text);
}
// Test attributes
_.each(validations.attributes, function(value, name) {
var attr = $el.attr(name);
should(attr).be.ok;
attr.should.be.equal(value);
});
});
});
+3
View File
@@ -0,0 +1,3 @@
# Readme
Default description for the book.
+1
View File
@@ -0,0 +1 @@
# Readme
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
"title": "js-config"
};
+1
View File
@@ -0,0 +1 @@
# Readme
+3
View File
@@ -0,0 +1,3 @@
{
"title": "json-config"
}
+10
View File
@@ -0,0 +1,10 @@
# Readme
### Relative
<p id="t1">{% include "./hello.md" %}</p>
### Git
<p id="t2">{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md" %}</p>
<p id="t3">{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test2.md" %}</p>
+1
View File
@@ -0,0 +1 @@
# Summary
+1
View File
@@ -0,0 +1 @@
Hello World
+13
View File
@@ -0,0 +1,13 @@
# Glossary
## test
Just a simple and easy to understand test.
## hakunamatata
This word is not present in the content.
## test long
This is a test with a longer text that the first entry to test order.
+10
View File
@@ -0,0 +1,10 @@
# Readme
The word test should be replaced by a glossary link.
```
But the word test should not be replaced in code blocks
```
The two words test long should be replaced by the correct glossary links.
+3
View File
@@ -0,0 +1,3 @@
# Summary
* [Page](folder/PAGE.md)
+3
View File
@@ -0,0 +1,3 @@
# Page
Just a page in a sub-directory to test relative link to glossary.
+18
View File
@@ -0,0 +1,18 @@
# Tests for Images
# SVG relative image
### Convert SVG to PNG
![test.svg](test.svg)
### Should only convert it once
![test.svg](test.svg)
### Download remote images
![remote image](http://upload.wikimedia.org/wikipedia/commons/b/b0/NewTux.svg)
### Remote images with same filename
![youtube1](http://img.youtube.com/vi/9bZkp7q19f0/0.jpg)
![youtube2](http://img.youtube.com/vi/IkV2HQLAKHY/0.jpg)
+3
View File
@@ -0,0 +1,3 @@
# Summary
* [Page](./folder/PAGE.md)
+3
View File
@@ -0,0 +1,3 @@
### Images from other folder
![test.svg](../test.svg)

Before

Width:  |  Height:  |  Size: 730 B

After

Width:  |  Height:  |  Size: 730 B

+3
View File
@@ -0,0 +1,3 @@
*
!SUMMARY.md
!.gitignore
+6
View File
@@ -0,0 +1,6 @@
# Summary
* [Hello](hello.md)
* [Hello 2](hello2.md)
* Hello 3
* [Hello 4](hello3/hello4.md)
+4
View File
@@ -0,0 +1,4 @@
# Language
* [English](en)
* [French](fr)
+1
View File
@@ -0,0 +1 @@
# Readme
+1
View File
@@ -0,0 +1 @@
Hello
+1
View File
@@ -0,0 +1 @@
# Summary
+1
View File
@@ -0,0 +1 @@
Bonjour
+1
View File
@@ -0,0 +1 @@
# Summary
+1
View File
@@ -0,0 +1 @@
# Readme
+4
View File
@@ -0,0 +1,4 @@
# Summary
* [Folder1](folder1/README.md)
* [Folder2](folder2/README.md)
+3
View File
@@ -0,0 +1,3 @@
# Folder 1
[Link to folder2](../folder2/README.md)
+1
View File
@@ -0,0 +1 @@
# Folder 2
+1
View File
@@ -0,0 +1 @@
# Page 1
+1
View File
@@ -0,0 +1 @@
# Readme
+5
View File
@@ -0,0 +1,5 @@
# Summary
* [Page 1](./PAGE1.md)
* [Page 2](./folder/PAGE2.md)
* [Don't exists](./NOTFOUND.md)
+1
View File
@@ -0,0 +1 @@
# Page 2
+26 -8
View File
@@ -1,14 +1,32 @@
var fs = require('fs');
var path = require('path');
var assert = require('assert');
var Book = require('../').Book;
describe('Configuration parsing', function () {
it('should correctly load from json', function() {
assert(books[0].options.title == "Test");
describe('Configuration', function () {
it('should extract default title from README', function() {
return books.parse("basic")
.then(function(book) {
book.options.title.should.be.equal("Readme");
});
});
it('should correctly load from javascript', function() {
assert(books[4].options.title == "Test 2");
it('should extract default description from README', function() {
return books.parse("basic")
.then(function(book) {
book.options.description.should.be.equal("Default description for the book.");
});
});
it('should correctly load from json (book.json)', function() {
return books.parse("config-json")
.then(function(book) {
book.options.title.should.be.equal("json-config");
});
});
it('should correctly load from JavaScript (book.js)', function() {
return books.parse("config-js")
.then(function(book) {
book.options.title.should.be.equal("js-config");
});
});
});
+43
View File
@@ -0,0 +1,43 @@
var fs = require('fs');
var path = require('path');
describe('ConRefs', function () {
var book, readme;
before(function() {
return books.generate("conrefs", "website")
.then(function(_book) {
book = _book;
readme = fs.readFileSync(
path.join(book.options.output, "index.html"),
{ encoding: "utf-8" }
);
});
});
it('should handle local references', function() {
readme.should.be.html({
".page-inner p#t1": {
count: 1,
text: "Hello World",
trim: true
}
});
});
it('should handle git references', function() {
readme.should.be.html({
".page-inner p#t2": {
count: 1,
text: "Hello from git",
trim: true
},
".page-inner p#t3": {
count: 1,
text: "First Hello. Hello from git",
trim: true
}
});
});
});
+17 -29
View File
@@ -1,36 +1,24 @@
var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var assert = require('assert');
var cheerio = require('cheerio');
var fs = require("fs");
var fsUtil = require("../lib/utils/fs");
describe('eBook generator', function () {
describe('Basic Book', function() {
var book;
before(function() {
return books.generate("basic", "ebook")
.then(function(_book) {
book = _book;
});
});
describe('eBook Generator', function () {
it('should correctly generate ebook pages', function(done) {
testGeneration(books[1], "ebook", function(output) {
assert(fs.existsSync(path.join(output, "SUMMARY.html")));
}, done);
});
it('should correctly output a SUMMARY.html', function() {
book.should.have.file("SUMMARY.html");
});
it('should correctly convert svg images to png', function(done) {
testGeneration(books[4], "ebook", function(output) {
// Check that all images exists
_.each([
"index.html",
"sub/PAGE.html"
], function(pageName) {
var pageFile = path.join(output, pageName);
var pageFolder = path.dirname(pageFile);
var pageContent = fs.readFileSync(pageFile, {encoding: "utf8"});
var $ = cheerio.load(pageContent);
$("img").each(function() {
var src = $(this).attr("src");
assert(fs.existsSync(path.resolve(pageFolder, src)), src+" not found for page "+pageName);
})
});
}, done);
it('should correctly copy assets', function() {
book.should.have.file("gitbook");
book.should.have.file("gitbook/style.css");
});
});
});
-6
View File
@@ -1,6 +0,0 @@
# Glossary
## Description
This is the dexcription of a description.
-3
View File
@@ -1,3 +0,0 @@
# Other Title
This is a description, it's simple, no ?
-1
View File
@@ -1 +0,0 @@
# Summary
-3
View File
@@ -1,3 +0,0 @@
{
"title": "Test"
}
-3
View File
@@ -1,3 +0,0 @@
body {
background: red;
}
-9
View File
@@ -1,9 +0,0 @@
# Test
a test text
# Test 2
a second test
-4
View File
@@ -1,4 +0,0 @@
# Test
This file is not parsed by gitbook because the structure is defined in book.json.
-6
View File
@@ -1,6 +0,0 @@
# Summary
* [Chapter 1](test.md)
* [Article 1](sub/test1.md)
* [Chapter 2](test2.md)
* [Google](https://www.google.com)
-5
View File
@@ -1,5 +0,0 @@
{
"structure": {
"readme": "intro.md"
}
}
-4
View File
@@ -1,4 +0,0 @@
# My Book
Test description
-8
View File
@@ -1,8 +0,0 @@
# This file is used to etst links transformations:
This is a relative link [test](../intro.md).
![image](../image.png)
This is a glossary link.
-4
View File
@@ -1,4 +0,0 @@
# Languages
* [English](en/)
* [French](fr/)
-2
View File
@@ -1,2 +0,0 @@
# Multi-Languages test
-1
View File
@@ -1 +0,0 @@
# English Book
-1
View File
@@ -1 +0,0 @@
# French Book
-4
View File
@@ -1,4 +0,0 @@
= My Book
Test description
-5
View File
@@ -1,5 +0,0 @@
= Summary
. link:test.adoc[Chapter 1]
.. link:test1.adoc[Article 1]
. link:test2.adoc[Chapter 2]
View File
View File
View File
-11
View File
@@ -1,11 +0,0 @@
# Other Title
A description
![test image to be converted](./test.svg)
![test url](http://upload.wikimedia.org/wikipedia/commons/b/b0/NewTux.svg)
![test image to be converted, second use](./test.svg)
# Test with youtube videos that have the same filename:
![youtube1](http://img.youtube.com/vi/9bZkp7q19f0/0.jpg)
![youtube2](http://img.youtube.com/vi/IkV2HQLAKHY/0.jpg)
-3
View File
@@ -1,3 +0,0 @@
# Summary
* [Page](sub/PAGE.md)
-3
View File
@@ -1,3 +0,0 @@
module.exports = {
title: "Test 2"
};
-18
View File
@@ -1,18 +0,0 @@
##
## Image from root page
![test image to be converted](../test.svg)
![test url](http://upload.wikimedia.org/wikipedia/commons/b/b0/NewTux.svg)
## Inline svg
{% html %}
<svg xmlns="http://www.w3.org/2000/svg">
<path d="M97.008198003228,6.103238498249268A97.2,97.2 0 0,1 87.9491894996971,41.385747140125076L54.289623147961166,25.546757493904366A60,60 0 0,0 59.88160370569629,3.7674311717588074Z"></path>
</svg>
{% endhtml %}
## Remote image
![remote url](http://upload.wikimedia.org/wikipedia/commons/a/af/Tux.png)
-5
View File
@@ -1,5 +0,0 @@
# Test Content inclusion
{% include "./test.md" %}
Git1:{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md" %}
Git2:{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test2.md" %}
-1
View File
@@ -1 +0,0 @@
Hello World
+17 -18
View File
@@ -1,32 +1,31 @@
var path = require('path');
var _ = require('lodash');
var assert = require('assert');
var fs = require("fs");
var git = require("../lib/utils/git");
var should = require('should');
var git = require('../lib/utils/git');
describe('GIT parser and getter', function () {
it('should correctly parse an https url', function() {
var parts = git.parseUrl("git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md");
assert(parts);
assert.equal(parts.host, "https://gist.github.com/69ea4542e4c8967d2fa7.git");
assert.equal(parts.ref, "master");
assert.equal(parts.filepath, "test.md");
should.exist(parts);
parts.host.should.be.equal("https://gist.github.com/69ea4542e4c8967d2fa7.git");
parts.ref.should.be.equal("master");
parts.filepath.should.be.equal("test.md");
});
it('should correctly parse an https url with a reference', function() {
var parts = git.parseUrl("git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md#0.1.2");
assert(parts);
assert.equal(parts.host, "https://gist.github.com/69ea4542e4c8967d2fa7.git");
assert.equal(parts.ref, "0.1.2");
assert.equal(parts.filepath, "test.md");
should.exist(parts);
parts.host.should.be.equal("https://gist.github.com/69ea4542e4c8967d2fa7.git");
parts.ref.should.be.equal("0.1.2");
parts.filepath.should.be.equal("test.md");
});
it('should correctly parse an ssh url', function() {
var parts = git.parseUrl("git+git@github.com:GitbookIO/gitbook.git/directory/README.md#e1594cde2c32e4ff48f6c4eff3d3d461743d74e1");
assert(parts);
assert.equal(parts.host, "git@github.com:GitbookIO/gitbook.git");
assert.equal(parts.ref, "e1594cde2c32e4ff48f6c4eff3d3d461743d74e1");
assert.equal(parts.filepath, "directory/README.md");
should.exist(parts);
parts.host.should.be.equal("git@github.com:GitbookIO/gitbook.git");
parts.ref.should.be.equal("e1594cde2c32e4ff48f6c4eff3d3d461743d74e1");
parts.filepath.should.be.equal("directory/README.md");
});
});
+78 -26
View File
@@ -1,35 +1,87 @@
var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var assert = require('assert');
var cheerio = require('cheerio');
var fs = require("fs");
var fsUtil = require("../lib/utils/fs");
describe('Glossary', function () {
describe('Parsing', function() {
var book;
before(function() {
return books.parse("glossary")
.then(function(_book) {
book = _book;
});
});
describe('Glossary Generation', function () {
it('should correctly replace glossary terms', function(done) {
testGeneration(books[0], "website", function(output) {
var content = fs.readFileSync(path.join(output, "index.html"), { encoding: "utf8" });
var $ = cheerio.load(content);
var $body = $(".page-inner");
var $a = $("a[href='GLOSSARY.html#description']");
assert($a.length == 1);
assert($a.text() == "description");
}, done);
it('should correctly list items', function() {
book.should.have.property("glossary");
book.glossary.should.have.lengthOf(3);
});
});
it('should correctly replace glossary terms in sub pages', function(done) {
testGeneration(books[1], "website", function(output) {
var content = fs.readFileSync(path.join(output, "sub/test1.html"), { encoding: "utf8" });
var $ = cheerio.load(content);
describe('Generation', function() {
var book;
var $body = $(".page-inner");
var $a = $("a[href='../GLOSSARY.html#test']");
assert($a.length == 1);
assert($a.text() == "test");
assert($a.attr("title") == "a test text");
}, done);
before(function() {
return books.generate("glossary", "website")
.then(function(_book) {
book = _book;
});
});
it('should correctly generate a GLOSSARY.html', function() {
book.should.have.file("GLOSSARY.html");
});
describe('Page Integration', function() {
var readme, page;
before(function() {
readme = fs.readFileSync(
path.join(book.options.output, "index.html"),
{ encoding: "utf-8" }
);
page = fs.readFileSync(
path.join(book.options.output, "folder/PAGE.html"),
{ encoding: "utf-8" }
);
});
it('should correctly replaced terms by links', function() {
readme.should.be.html({
".page-inner a[href='GLOSSARY.html#test']": {
count: 1,
text: "test",
attributes: {
title: "Just a simple and easy to understand test."
}
}
});
});
it('should correctly replaced terms by links (relative)', function() {
page.should.be.html({
".page-inner a[href='../GLOSSARY.html#test']": {
count: 1
}
});
});
it('should not replace terms in codeblocks', function() {
readme.should.be.html({
".page-inner code a": {
count: 0
}
});
});
it('should correctly select the longest term', function() {
readme.should.be.html({
".page-inner a[href='GLOSSARY.html#test_long']": {
count: 1,
text: "test long"
}
});
});
});
});
});
+55 -49
View File
@@ -1,62 +1,68 @@
var os = require('os');
var path = require('path');
var Q = require('q');
var fs = require('fs');
var _ = require('lodash');
var should = require('should');
var fsUtil = require("../lib/utils/fs");
var fsUtil = require('../lib/utils/fs');
var Book = require('../').Book;
var LOG_LEVELS = require('../').LOG_LEVELS;
// Nicety for mocha / Q
global.qdone = function qdone(promise, done) {
return promise.then(function() {
return done();
}, function(err) {
return done(err);
}).done();
require("./assertions");
var BOOKS = {};
var TMPDIR = os.tmpdir();
// Generate and return a book
function generateBook(bookId, test) {
return parseBook(bookId, test)
.then(function(book) {
return book.generate(test)
.thenResolve(book);
});
}
// Generate and return a book
function parseBook(bookId, test) {
test = test || "website";
BOOKS[bookId] = BOOKS[bookId] || {};
if (BOOKS[bookId][test]) return Q(BOOKS[bookId][test]);
BOOKS[bookId][test] = new Book(path.resolve(__dirname, "books", bookId), {
logLevel: LOG_LEVELS.DISABLED,
config: {
output: path.resolve(TMPDIR, bookId+"-"+test)
}
});
return BOOKS[bookId][test].parse()
.then(function() {
return BOOKS[bookId][test];
});
}
global.books = {
parse: parseBook,
generate: generateBook
};
// Test generation of a book
global.testGeneration = function(book, type, func, done) {
var OUTPUT_PATH = book.options.output;
qdone(
book.generate(type)
.then(function() {
func(OUTPUT_PATH);
})
.fin(function() {
return fsUtil.remove(OUTPUT_PATH);
}),
done);
};
// Books for testings
var books = fs.readdirSync(path.join(__dirname, './fixtures/'));
global.books = _.chain(books)
.sortBy()
.map(function(book) {
if (book.indexOf("test") !== 0) return null;
return new Book(path.join(__dirname, './fixtures/', book), {
logLevel: LOG_LEVELS.DISABLED
});
})
.compact()
.value();
// Init before doing tests
before(function(done) {
qdone(
_.reduce(global.books, function(prev, book) {
// Cleanup all tests
after(function() {
return _.chain(BOOKS)
.map(function(types, bookId) {
return _.values(types);
})
.flatten()
.reduce(function(prev, book) {
return prev.then(function() {
return fsUtil.remove(path.join(book.root, "_book"));
return fsUtil.remove(book.options.output);
})
.then(function() {
return book.parse();
});
}, Q()),
done
);
}, Q())
.value();
});
+56
View File
@@ -0,0 +1,56 @@
var fs = require('fs');
var _ = require('lodash');
var path = require('path');
var cheerio = require('cheerio');
describe('Images', function () {
var book, readme, $, $img, srcs;
before(function() {
return books.generate("images", "ebook")
.then(function(_book) {
book = _book;
readme = fs.readFileSync(
path.join(book.options.output, "index.html"),
{ encoding: "utf-8" }
);
$ = cheerio.load(readme);
$img = $("img");
srcs = $img.map(function() { return $(this).attr("src"); })
});
});
it('should detect all images', function() {
_.uniq(srcs).should.have.lengthOf(4);
});
it('should keep image tags', function() {
srcs.should.have.lengthOf(5);
});
it('should not have .svg files', function() {
_.each(srcs, function(src) {
path.extname(src).should.not.equal(".svg");
});
});
it('should correctly convert svg images to png', function() {
_.each(srcs, function(src) {
book.should.have.file(src);
});
});
it('should handle relative paths', function() {
var PAGE = fs.readFileSync(
path.join(book.options.output, "folder/PAGE.html"),
{ encoding: "utf-8" }
);
PAGE.should.be.html({
"img[src='../test.png']": {
count: 1
}
});
});
});
+23
View File
@@ -0,0 +1,23 @@
var fs = require('fs');
var path = require('path');
var should = require('should');
var Book = require('../').Book;
var LOG_LEVELS = require('../').LOG_LEVELS;
describe('Init Books', function () {
var initRoot;
before(function() {
initRoot = path.resolve(__dirname, "books/init");
return Book.init(initRoot, {
logLevel: LOG_LEVELS.DISABLED,
});
});
it('should create all chapters', function() {
should(fs.existsSync(path.resolve(initRoot, "hello.md"))).be.ok;
should(fs.existsSync(path.resolve(initRoot, "hello2.md"))).be.ok;
should(fs.existsSync(path.resolve(initRoot, "hello3/hello4.md"))).be.ok;
});
});
+79 -46
View File
@@ -1,59 +1,92 @@
var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var assert = require('assert');
var fs = require("fs");
describe('JSON generator', function () {
it('should correctly generate a book to json with glossary', function(done) {
testGeneration(books[0], "json", function(output) {
assert(fs.existsSync(path.join(output, "README.json")));
describe('Basic Book', function() {
var book;
var readme = JSON.parse(fs.readFileSync(path.join(output, "README.json")));
assert(readme.sections[0].content.indexOf('class="glossary-term"') > 0);
}, done);
before(function() {
return books.generate("basic", "json")
.then(function(_book) {
book = _book;
});
});
it('should correctly output a README.json', function() {
book.should.have.file("README.json");
});
it('should output a valid json', function() {
book.should.have.jsonfile("README.json");
});
describe('Page Format', function() {
var page;
before(function() {
page = JSON.parse(
fs.readFileSync(
path.join(book.options.output, "README.json"),
{ encoding: "utf-8" }
)
);
});
it('should contains valid section', function() {
page.should.have.property("sections").with.lengthOf(1);
page.sections[0].should.have.property("content").which.is.a.String;
page.sections[0].should.have.property("type").which.is.a.String.which.equal("normal");
});
it('should contains valid progress', function() {
page.should.have.property("progress");
page.progress.should.have.property("chapters").with.lengthOf(1);
page.progress.should.have.property("current");
});
it('should contains no languages', function() {
page.should.have.property("langs").with.lengthOf(0);
});
});
});
it('should correctly generate a book to json with sub folders', function(done) {
testGeneration(books[1], "json", function(output) {
assert(fs.existsSync(path.join(output, "README.json")));
assert(fs.existsSync(path.join(output, "intro.json")));
assert(fs.existsSync(path.join(output, "sub/test1.json")));
describe('Multilingual Book', function() {
var book;
var test1 = JSON.parse(fs.readFileSync(path.join(output, "sub/test1.json")));
assert(test1.sections[0].content.indexOf("index.html") > 0);
}, done);
});
before(function() {
return books.generate("languages", "json")
.then(function(_book) {
book = _book;
});
});
it('should correctly generate a multilingual book to json', function(done) {
testGeneration(books[2], "json", function(output) {
assert(fs.existsSync(path.join(output, "README.json")));
assert(fs.existsSync(path.join(output, "en/README.json")));
assert(fs.existsSync(path.join(output, "fr/README.json")));
}, done);
});
it('should correctly output READMEs', function() {
book.should.have.file("README.json");
book.should.have.file("en/README.json");
book.should.have.file("fr/README.json");
});
it('should correctly generate an asciidoc book to json', function(done) {
testGeneration(books[3], "json", function(output) {
assert(fs.existsSync(path.join(output, "README.json")));
assert(fs.existsSync(path.join(output, "test.json")));
assert(fs.existsSync(path.join(output, "test1.json")));
assert(fs.existsSync(path.join(output, "test2.json")));
}, done);
});
it('should output valid json', function() {
book.should.have.jsonfile("README.json");
book.should.have.jsonfile("en/README.json");
book.should.have.jsonfile("fr/README.json");
});
it('should correctly generate a book with local inclusion', function(done) {
testGeneration(books[5], "json", function(output) {
var readme = JSON.parse(fs.readFileSync(path.join(output, "README.json")));
assert(readme.sections[0].content.indexOf('Hello World') > 0);
}, done);
});
describe('Page Format', function() {
var page;
it('should correctly generate a book with external inclusion', function(done) {
testGeneration(books[5], "json", function(output) {
var readme = JSON.parse(fs.readFileSync(path.join(output, "README.json")));
assert(readme.sections[0].content.indexOf('Git1:Hello from git') > 0);
assert(readme.sections[0].content.indexOf('Git2:First Hello. Hello from git') > 0);
}, done);
before(function() {
page = JSON.parse(
fs.readFileSync(
path.join(book.options.output, "README.json"),
{ encoding: "utf-8" }
)
);
});
it('should contains no languages', function() {
page.should.have.property("langs").with.lengthOf(2);
});
});
});
});
+40
View File
@@ -0,0 +1,40 @@
var fs = require('fs');
var path = require('path');
describe('Languages', function () {
describe('Parsing', function() {
var book;
before(function() {
return books.parse("languages")
.then(function(_book) {
book = _book;
});
});
it('should correctly list languages', function() {
book.should.have.property("books");
book.books.should.have.lengthOf(2);
book.books[0].options.language.should.be.equal("en");
book.books[1].options.language.should.be.equal("fr");
});
});
describe('Generation', function() {
var book;
before(function() {
return books.generate("languages", "website")
.then(function(_book) {
book = _book;
});
});
it('should correctly create books', function() {
book.should.have.file("index.html");
book.should.have.file("en/index.html");
book.should.have.file("fr/index.html");
});
});
});
+44 -19
View File
@@ -1,40 +1,65 @@
var path = require('path');
var should = require('should');
var fs = require('fs');
var _ = require('lodash');
var assert = require('assert');
var path = require('path');
var cheerio = require('cheerio');
var links = require("../lib/utils/links");
describe('Links', function () {
it('should correctly test external links', function() {
assert(links.isExternal("http://google.fr"));
assert(links.isExternal("https://google.fr"));
assert(!links.isExternal("test.md"));
assert(!links.isExternal("folder/test.md"));
assert(!links.isExternal("/folder/test.md"));
links.isExternal("http://google.fr").should.be.exactly(true);
links.isExternal("https://google.fr").should.be.exactly(true);
links.isExternal("test.md").should.be.exactly(false);
links.isExternal("folder/test.md").should.be.exactly(false);
links.isExternal("/folder/test.md").should.be.exactly(false);
});
it('should correctly test anchor links', function() {
assert(links.isAnchor("#test"));
assert(links.isAnchor(" #test"));
assert(!links.isAnchor("https://google.fr#test"));
assert(!links.isAnchor("test.md#test"));
it('should correctly detect anchor links', function() {
links.isAnchor("#test").should.be.exactly(true);
links.isAnchor(" #test").should.be.exactly(true);
links.isAnchor("https://google.fr#test").should.be.exactly(false);
links.isAnchor("test.md#test").should.be.exactly(false);
});
describe('toAbsolute', function() {
it('should correctly transform as absolute', function() {
assert.equal(links.toAbsolute("http://google.fr"), "http://google.fr");
assert.equal(links.toAbsolute("test.md", "./", "./"), "test.md");
assert.equal(links.toAbsolute("folder/test.md", "./", "./"), "folder/test.md");
links.toAbsolute("http://google.fr").should.be.equal("http://google.fr");
links.toAbsolute("test.md", "./", "./").should.be.equal("test.md");
links.toAbsolute("folder/test.md", "./", "./").should.be.equal("folder/test.md");
});
it('should correctly handle windows path', function() {
assert.equal(links.toAbsolute("folder\\test.md", "./", "./"), "folder/test.md");
links.toAbsolute("folder\\test.md", "./", "./").should.be.equal("folder/test.md");
});
it('should correctly handle absolute path', function() {
assert.equal(links.toAbsolute("/test.md", "./", "./"), "test.md");
assert.equal(links.toAbsolute("/test.md", "test", "test"), "../test.md");
assert.equal(links.toAbsolute("/sub/test.md", "test", "test"), "../sub/test.md");
links.toAbsolute("/test.md", "./", "./").should.be.equal("test.md");
links.toAbsolute("/test.md", "test", "test").should.be.equal("../test.md");
links.toAbsolute("/sub/test.md", "test", "test").should.be.equal("../sub/test.md");
});
});
describe('page', function() {
var book;
before(function() {
return books.generate("links", "website")
.then(function(_book) {
book = _book;
});
});
it('should correctly replace relative links', function() {
var readme = fs.readFileSync(
path.join(book.options.output, "folder1/index.html"),
{ encoding: "utf-8" }
);
var $ = cheerio.load(readme);
var $a = $(".page-inner a");
$a.attr('href').should.be.exactly("../folder2/index.html");
})
});
});
-82
View File
@@ -1,82 +0,0 @@
var path = require('path');
var _ = require('lodash');
var assert = require('assert');
describe('Book parsing', function () {
it('should correctly parse the readme', function() {
assert.equal(books[1].options.title, 'My Book');
assert.equal(books[1].options.description, 'Test description');
});
it('should correctly parse the readme with asciidoc', function() {
assert.equal(books[3].options.title, 'My Book');
assert.equal(books[3].options.description, 'Test description');
});
it('should correctly parse the summary', function() {
var LEXED = books[1].summary;
assert.equal(LEXED.chapters[0].path, 'intro.md');
assert.equal(LEXED.chapters[0].exists, true);
assert.equal(LEXED.chapters[0].introduction, true);
assert.equal(LEXED.chapters[0].external, false);
assert.equal(LEXED.chapters[1].path, 'test.md');
assert.equal(LEXED.chapters[1].exists, false);
assert.equal(LEXED.chapters[1].introduction, false);
assert.equal(LEXED.chapters[1].external, false);
assert.equal(LEXED.chapters[2].path, 'test2.md');
assert.equal(LEXED.chapters[2].exists, false);
assert.equal(LEXED.chapters[2].introduction, false);
assert.equal(LEXED.chapters[2].external, false);
assert.equal(LEXED.chapters[3].path, 'https://www.google.com');
assert.equal(LEXED.chapters[3].exists, true);
assert.equal(LEXED.chapters[3].introduction, false);
assert.equal(LEXED.chapters[3].external, true);
});
it('should correctly parse the glossary', function() {
var LEXED = books[1].glossary;
assert.equal(LEXED[0].id, "test");
assert.equal(LEXED[0].name, "Test");
assert.equal(LEXED[0].description, "a test text");
assert.equal(LEXED[1].id, "test_2");
assert.equal(LEXED[1].name, "Test 2");
assert.equal(LEXED[1].description, "a second test");
});
it('should correctly parse list of files', function() {
var FILES = books[1].files;
assert.deepEqual(FILES, [ 'README.md', 'intro.md', 'sub/', 'sub/test1.md' ]);
});
it('should correctly parse the languages', function() {
assert.equal(books[2].books.length, 2);
assert(books[2].isMultilingual());
assert.equal(books[2].books[0].options.language, "en");
assert.equal(books[2].books[0].options.title, "English Book");
assert.equal(books[2].books[1].options.language, "fr");
assert.equal(books[2].books[1].options.title, "French Book");
});
it('should correctly parse the navigation', function() {
var NAVIGATION = books[1].navigation;
assert.equal(_.size(NAVIGATION), 2);
assert(NAVIGATION["intro.md"])
assert.equal(NAVIGATION["intro.md"].title, "");
assert.equal(NAVIGATION["intro.md"].prev, null);
assert.equal(NAVIGATION["intro.md"].next.title, "Article 1");
assert.equal(NAVIGATION["sub/test1.md"].title, "Article 1");
assert.equal(NAVIGATION["sub/test1.md"].prev.title, "");
assert.equal(NAVIGATION["sub/test1.md"].next, null);
});
});
+133 -132
View File
@@ -1,189 +1,190 @@
var path = require('path');
var _ = require('lodash');
var assert = require('assert');
var fs = require("fs");
var should = require('should');
var path = require('path');
var Plugin = require("../lib/plugin");
var PLUGINS_ROOT = path.resolve(__dirname, "plugins");
var Plugin = require('../lib/plugin');
var PLUGINS_ROOT = path.resolve(__dirname, 'plugins');
describe('Plugins', function () {
describe('invalid plugin', function() {
it('should signal as invalid', function() {
var plugin = new Plugin(books[0], "invalid");
var book;
before(function() {
return books.parse("basic")
.then(function(_book) {
book = _book;
});
});
describe('Invalid', function() {
var plugin;
before(function() {
plugin = new Plugin(book, "invalid");
plugin.load("./invalid", PLUGINS_ROOT);
assert(!plugin.isValid());
});
it('should be detected', function() {
should(plugin.isValid()).be.exactly(false);
});
});
describe('empty plugin', function() {
var plugin = new Plugin(books[0], "invalid");
plugin.load("./empty", PLUGINS_ROOT);
describe('Empty', function() {
var plugin;
it('should valid a plugin', function() {
assert(plugin.isValid());
before(function() {
plugin = new Plugin(book, "empty");
plugin.load("./empty", PLUGINS_ROOT);
});
it('should return an empty list of resources', function(done) {
qdone(
plugin.getResources()
.then(function(resources) {
_.each(Plugin.RESOURCES, function(resName) {
assert.equal(resources[resName].length, 0);
it('should valid a plugin', function() {
should(plugin.isValid()).be.exactly(true);
});
it('should return an empty list of resources', function() {
return plugin.getResources()
.then(function(resources) {
_.each(Plugin.RESOURCES, function(resName) {
resources[resName].should.have.lengthOf(0);
});
});
});
});
describe('Resources', function() {
var plugin;
before(function() {
plugin = new Plugin(book, "resources");
plugin.load("./resources", PLUGINS_ROOT);
return book.plugins.load(plugin);
});
it('should valid a plugin', function() {
should(plugin.isValid()).be.exactly(true);
});
describe('Website', function() {
it('should return a valid list of resources', function() {
return plugin.getResources("website")
.then(function(resources) {
resources["js"].should.have.lengthOf(1);
});
}),
done);
});
it('should extend books plugins', function() {
var resources = book.plugins.resources("website");
resources["js"].should.have.lengthOf(1);
});
});
describe('eBook', function() {
it('should return a valid list of resources', function() {
return plugin.getResources("ebook")
.then(function(resources) {
resources["css"].should.have.lengthOf(1);
});
});
it('should extend books plugins', function() {
var resources = book.plugins.resources("ebook");
resources["css"].should.have.lengthOf(1);
});
});
});
describe('resources plugin', function() {
var plugin = new Plugin(books[0], "resources");
plugin.load("./resources", PLUGINS_ROOT);
describe('Filters', function() {
var plugin;
before(function(done) {
qdone(books[0].plugins.load(plugin), done);
before(function() {
plugin = new Plugin(book, "filters");
plugin.load("./filters", PLUGINS_ROOT);
return book.plugins.load(plugin);
});
it('should valid a plugin', function() {
assert(plugin.isValid());
});
it('should return a valid list of resources (website)', function(done) {
qdone(
plugin.getResources("website")
.then(function(resources) {
assert.equal(resources["js"].length, 1);
}),
done);
});
it('should return a valid list of resources (ebook)', function(done) {
qdone(
plugin.getResources("ebook")
.then(function(resources) {
assert.equal(resources["css"].length, 1);
}),
done);
});
it('should extend books plugins (website)', function() {
var resources = books[0].plugins.resources("website");
assert.equal(resources["js"].length, 1);
});
it('should extend books plugins (ebook)', function() {
var resources = books[0].plugins.resources("ebook");
assert.equal(resources["css"].length, 1);
});
});
describe('filters', function() {
var plugin = new Plugin(books[0], "filters");
plugin.load("./filters", PLUGINS_ROOT);
before(function(done) {
qdone(books[0].plugins.load(plugin), done);
});
it('should valid a plugin', function() {
assert(plugin.isValid());
should(plugin.isValid()).be.exactly(true);
});
it('should return a map of filters', function() {
var filters = plugin.getFilters();
assert.equal(_.size(filters), 2);
assert(filters["hello"]);
assert(filters["helloCtx"]);
_.size(filters).should.equal(2);
filters.should.have.property("hello");
filters.should.have.property("helloCtx");
});
it('should correctly extend template filters', function(done) {
qdone(
books[0].template.renderString('{{ "World"|hello }}')
it('should correctly extend template filters', function() {
return book.template.renderString('{{ "World"|hello }}')
.then(function(content) {
assert.equal(content, "Hello World");
}),
done
);
content.should.equal("Hello World");
});
});
it('should correctly set book as context', function(done) {
qdone(
books[0].template.renderString('{{ "root"|helloCtx }}')
it('should correctly set book as context', function() {
return book.template.renderString('{{ "root"|helloCtx }}')
.then(function(content) {
assert.equal(content, "root:"+books[0].root);
}),
done
);
content.should.equal("root:"+book.root);
});
});
});
describe('blocks', function() {
var plugin = new Plugin(books[0], "blocks");
plugin.load("./blocks", PLUGINS_ROOT);
describe('Blocks', function() {
var plugin;
before(function() {
plugin = new Plugin(book, "blocks");
plugin.load("./blocks", PLUGINS_ROOT);
return book.plugins.load(plugin);
});
var testTpl = function(str, args, options) {
return books[0].template.renderString(str, args, options)
.then(books[0].template.postProcess)
return book.template.renderString(str, args, options)
.then(book.template.postProcess)
};
before(function(done) {
qdone(books[0].plugins.load(plugin), done);
});
it('should valid a plugin', function() {
assert(plugin.isValid());
should(plugin.isValid()).be.exactly(true);
});
it('should correctly extend template blocks', function(done) {
qdone(
testTpl('{% test %}hello{% endtest %}')
it('should correctly extend template blocks', function() {
return testTpl('{% test %}hello{% endtest %}')
.then(function(content) {
assert.equal(content, "testhellotest");
}),
done
);
content.should.equal("testhellotest");
});
});
it('should correctly accept shortcuts', function(done) {
qdone(
testTpl('$$hello$$', {}, {
it('should correctly accept shortcuts', function() {
return testTpl('$$hello$$', {}, {
type: "markdown"
})
.then(function(content) {
assert.equal(content, "testhellotest");
}),
done
);
content.should.equal("testhellotest");
});
});
it('should correctly extend template blocks with defined end', function(done) {
qdone(
testTpl('{% test2 %}hello{% endtest2end %}')
it('should correctly extend template blocks with defined end', function() {
return testTpl('{% test2 %}hello{% endtest2end %}')
.then(function(content) {
assert.equal(content, "test2hellotest2");
}),
done
);
content.should.equal("test2hellotest2");
});
});
it('should correctly extend template blocks with sub-blocks', function(done) {
qdone(
testTpl('{% test3join separator=";" %}hello{% also %}world{% endtest3join %}')
it('should correctly extend template blocks with sub-blocks', function() {
return testTpl('{% test3join separator=";" %}hello{% also %}world{% endtest3join %}')
.then(function(content) {
assert.equal(content, "hello;world");
}),
done
);
content.should.equal("hello;world");
});
});
it('should correctly extend template blocks with different sub-blocks', function(done) {
qdone(
testTpl('{% test4join separator=";" %}hello{% also %}the{% finally %}world{% endtest4join %}')
it('should correctly extend template blocks with different sub-blocks', function() {
return testTpl('{% test4join separator=";" %}hello{% also %}the{% finally %}world{% endtest4join %}')
.then(function(content) {
assert.equal(content, "hello;the;world");
}),
done
);
content.should.equal("hello;the;world");
});
});
});
});
+70
View File
@@ -0,0 +1,70 @@
var fs = require('fs');
var path = require('path');
describe('Summary', function () {
describe('Parsing', function() {
var book;
before(function() {
return books.parse("summary")
.then(function(_book) {
book = _book;
});
});
it('should correctly list items', function() {
book.should.have.property("summary");
book.summary.should.have.property("chapters");
book.summary.chapters.should.have.lengthOf(4);
});
it('should correctly mark non-existant entries', function() {
book.summary.chapters[0].exists.should.have.equal(true);
book.summary.chapters[1].exists.should.have.equal(true);
book.summary.chapters[2].exists.should.have.equal(true);
book.summary.chapters[3].exists.should.have.equal(false);
});
});
describe('Generation', function() {
var book;
before(function() {
return books.generate("summary", "website")
.then(function(_book) {
book = _book;
});
});
it('should create files according to summary', function() {
book.should.have.file("index.html");
book.should.have.file("PAGE1.html");
book.should.have.file("folder/PAGE2.html");
});
it('should correctly output summary', function() {
var PAGE = fs.readFileSync(
path.join(book.options.output, "index.html"),
{ encoding: "utf-8" }
);
PAGE.should.be.html({
".book-summary .chapter[data-level='0'] a": {
attributes: {
href: "./index.html"
}
},
".book-summary .chapter[data-level='1'] a": {
attributes: {
href: "./PAGE1.html"
}
},
".book-summary .chapter[data-level='2'] a": {
attributes: {
href: "./folder/PAGE2.html"
}
}
});
});
});
});
+22 -26
View File
@@ -1,37 +1,33 @@
var path = require('path');
var _ = require('lodash');
var assert = require('assert');
var fs = require("fs");
var pkg = require("../package.json");
describe('Templating', function () {
before(function(done) {
testGeneration(books[0], "website", function(output) {}, done);
var book;
before(function() {
return books.parse("basic")
.then(function(_book) {
book = _book;
});
});
var testTpl = function(str, args, options) {
return books[0].template.renderString(str, args, options)
.then(books[0].template.postProcess)
return book.template.renderString(str, args, options)
.then(book.template.postProcess)
};
it('should correctly have access to generator', function(done) {
qdone(
testTpl('{{ gitbook.generator }}')
.then(function(content) {
assert.equal(content, "website");
}),
done
);
});
describe('Context', function() {
it('should correctly have access to generator', function() {
return testTpl('{{ gitbook.generator }}')
.then(function(content) {
content.should.equal("website");
});
});
it('should correctly have access to gitbook version', function(done) {
qdone(
testTpl('{{ gitbook.version }}')
.then(function(content) {
assert.equal(content, pkg.version.toString());
}),
done
);
it('should correctly have access to gitbook version', function() {
return testTpl('{{ gitbook.version }}')
.then(function(content) {
content.should.equal(pkg.version.toString());
});
});
});
});
+18 -33
View File
@@ -1,40 +1,25 @@
var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var assert = require('assert');
var fs = require("fs");
var fsUtil = require("../lib/utils/fs");
describe('Website generator', function () {
describe('Basic Book', function() {
var book;
before(function() {
return books.generate("basic", "website")
.then(function(_book) {
book = _book;
});
});
describe('Website Generator', function () {
it('should correctly generate a book to website', function(done) {
testGeneration(books[1], "website", function(output) {
assert(fs.existsSync(path.join(output, "index.html")));
assert(fs.existsSync(path.join(output, "search_index.json")));
}, done);
});
it('should correctly output an index.html', function() {
book.should.have.file("index.html");
});
it('should correctly include styles in website', function(done) {
testGeneration(books[0], "website", function(output) {
assert(fs.existsSync(path.join(output, "styles/website.css")));
var INDEX = fs.readFileSync(path.join(output, "index.html")).toString();
assert(INDEX.indexOf("styles/website.css") > 0);
}, done);
});
it('should correctly include glossary in website', function(done) {
testGeneration(books[0], "website", function(output) {
assert(fs.existsSync(path.join(output, "GLOSSARY.html")));
}, done);
});
it('should correctly generate a multilingual book to website', function(done) {
testGeneration(books[2], "website", function(output) {
assert(fs.existsSync(path.join(output, "index.html")));
assert(fs.existsSync(path.join(output, "gitbook")));
assert(fs.existsSync(path.join(output, "fr/index.html")));
assert(fs.existsSync(path.join(output, "en/index.html")));
}, done);
it('should correctly copy assets', function() {
book.should.have.file("gitbook");
book.should.have.file("gitbook/app.js");
book.should.have.file("gitbook/style.css");
});
});
});
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -12,7 +12,7 @@
"SEARCH_PLACEHOLDER": "اكتب للبحث",
"FONTSETTINGS_TOGGLE": "إعدادات الخط",
"SHARE_TOGGLE": "حصة",
"SHARE_ON": "على __platform__ حصة",
"SHARE_ON": "على {{platform}} حصة",
"FONTSETTINGS_WHITE": "أبيض",
"FONTSETTINGS_SEPIA": "بني داكن",
"FONTSETTINGS_NIGHT": "ليل",
+1 -1
View File
@@ -11,7 +11,7 @@
"SEARCH_PLACEHOLDER": "অনুসন্ধান",
"FONTSETTINGS_TOGGLE": "ফন্ট সেটিংস",
"SHARE_TOGGLE": "শেয়ার",
"SHARE_ON": "__platform__-এ শেয়ার",
"SHARE_ON": "{{platform}}-এ শেয়ার",
"FONTSETTINGS_WHITE": "সাদা",
"FONTSETTINGS_SEPIA": "সেপিয়া",
"FONTSETTINGS_NIGHT": "রাত",
+1 -1
View File
@@ -11,7 +11,7 @@
"SEARCH_PLACEHOLDER": "Suchbegriff eingeben",
"FONTSETTINGS_TOGGLE": "Schrifteinstellungen",
"SHARE_TOGGLE": "Teilen",
"SHARE_ON": "Auf __platform__ teilen",
"SHARE_ON": "Auf {{platform}} teilen",
"FONTSETTINGS_WHITE": "Hell",
"FONTSETTINGS_SEPIA": "Sepia",
"FONTSETTINGS_NIGHT": "Nacht",
+1 -1
View File
@@ -11,7 +11,7 @@
"SEARCH_PLACEHOLDER": "Type to search",
"FONTSETTINGS_TOGGLE": "Font Settings",
"SHARE_TOGGLE": "Share",
"SHARE_ON": "Share on __platform__",
"SHARE_ON": "Share on {{platform}}",
"FONTSETTINGS_WHITE": "White",
"FONTSETTINGS_SEPIA": "Sepia",
"FONTSETTINGS_NIGHT": "Night",
+1 -1
View File
@@ -11,7 +11,7 @@
"SEARCH_PLACEHOLDER": "Escribe para buscar",
"FONTSETTINGS_TOGGLE": "Configuración de fuente",
"SHARE_TOGGLE": "Comparte",
"SHARE_ON": "Comparte en __platform__",
"SHARE_ON": "Comparte en {{platform}}",
"FONTSETTINGS_WHITE": "Claro",
"FONTSETTINGS_SEPIA": "Sépia",
"FONTSETTINGS_NIGHT": "Noche",

Some files were not shown because too many files have changed in this diff Show More