mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-26 12:18:01 +00:00
Compare commits
150 Commits
2.0.0-beta.5
...
2.3.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 53af8b2bb6 | |||
| bd885b135f | |||
| 62a6dde81a | |||
| 14b72b344f | |||
| ac03668063 | |||
| 2512e176c9 | |||
| b613393866 | |||
| 607a6e95de | |||
| 871f574ff7 | |||
| 377e470b15 | |||
| e0a3f0cea5 | |||
| 66727b2736 | |||
| 8215ad977f | |||
| a611dffbdf | |||
| 39f378d8cf | |||
| f00da58153 | |||
| 09b038b16d | |||
| cf601d97ad | |||
| 80edad53d4 | |||
| a972b32769 | |||
| efcaae3e60 | |||
| e0ee591638 | |||
| 310a6d909f | |||
| cefd8fc50f | |||
| a4422593f2 | |||
| e2c5d22756 | |||
| 84385d9dc3 | |||
| 6cfa4c8ab7 | |||
| c76ccc53e1 | |||
| d48eafb1a2 | |||
| 302d9b4b91 | |||
| a091a7f68b | |||
| 53621f6de3 | |||
| 288b965db3 | |||
| 578c9dcfc6 | |||
| 64de17b248 | |||
| 501843d624 | |||
| 508ce4283e | |||
| 4aa8e66549 | |||
| 917a6f70d8 | |||
| 2f5e53da55 | |||
| c3cdefc90a | |||
| 9c580e4989 | |||
| 50c902c4e4 | |||
| 84b6e0bde6 | |||
| abc29c3fba | |||
| 8356c534f5 | |||
| 78ff2687b4 | |||
| 9b6586fb36 | |||
| ea133219d0 | |||
| c9b5d81a3c | |||
| d895c63211 | |||
| 8c86da67ca | |||
| a9a230dfc3 | |||
| 6d53e52771 | |||
| 52e10b7cfe | |||
| addac85696 | |||
| 13fb949d68 | |||
| f1b593cfbd | |||
| f998e2dec9 | |||
| 2c0bd53a91 | |||
| 6dd7f6162f | |||
| 475b0bb2b3 | |||
| e6343935e3 | |||
| 946883fd4c | |||
| b1b7e3148b | |||
| 32203f6438 | |||
| f2d3c5d2ed | |||
| 7e2f0ed4bc | |||
| a877acf905 | |||
| ac756ddf7e | |||
| 36e2236e6b | |||
| 72df665520 | |||
| 07785528a5 | |||
| bb579dd581 | |||
| a7d3064340 | |||
| 1a60778248 | |||
| cda4bb5bda | |||
| 7543781046 | |||
| 82f3ffad06 | |||
| dc4d2a1731 | |||
| 2523925915 | |||
| d5bbd8475c | |||
| 54d195268a | |||
| a0deb9509f | |||
| b0b1433594 | |||
| 17a2c0a37c | |||
| fd68ea1cc2 | |||
| 784874c776 | |||
| f45c6d3466 | |||
| 98af70902f | |||
| 41a67b5c4c | |||
| 83ee903af4 | |||
| e591b0e485 | |||
| bcc9a34742 | |||
| 6b56c7de7f | |||
| 7b42719699 | |||
| 64b8343f67 | |||
| fcc5089fa6 | |||
| 334f782aa8 | |||
| 1776f2bf77 | |||
| e259412f79 | |||
| 999a02f110 | |||
| 604d0fba65 | |||
| 0e8f7b870b | |||
| 1eebc9a46e | |||
| 0a94c80c44 | |||
| c70bb2fbd8 | |||
| 12c06b384f | |||
| 82a58e7ac3 | |||
| dcb56ef433 | |||
| 8da91de514 | |||
| 4b20685562 | |||
| fff7c5cc3a | |||
| 3065742b73 | |||
| ffd69ad1f2 | |||
| 9004011479 | |||
| 1046bb4133 | |||
| 5578505213 | |||
| a61f56662a | |||
| f42e48be03 | |||
| f640e101ba | |||
| b7da276ae0 | |||
| bf7c0989f5 | |||
| 65fdbe7f55 | |||
| c9af209a93 | |||
| 48ab44a776 | |||
| b2e684af8f | |||
| b38a2c11a4 | |||
| c31acef47a | |||
| e9a573e18a | |||
| c07ddc77f7 | |||
| 303fc992d4 | |||
| 4b7797f61b | |||
| f775d41933 | |||
| 7722e7bdfa | |||
| 346c05f0de | |||
| 73c69923b3 | |||
| afbca4bdf5 | |||
| b61371942b | |||
| 61c07e8876 | |||
| d317741144 | |||
| 275739a778 | |||
| cb3a43ed8a | |||
| ec8d1d8fc9 | |||
| 868a3186dd | |||
| 17b546181c | |||
| 2d1aa15af8 | |||
| 63ee94ff89 | |||
| 7d9dc08a38 |
+25
-10
@@ -21,22 +21,37 @@ Translators
|
||||
------------
|
||||
|
||||
- German
|
||||
- Winnie (@winniehell)
|
||||
- Winnie (@winniehell)
|
||||
- Italian
|
||||
- Giulio Bonanome (@gbonanome)
|
||||
- Giulio Bonanome (@gbonanome)
|
||||
- Russian
|
||||
- Andrey Akinshin (@AndreyAkinshin)
|
||||
- Andrey Akinshin (@AndreyAkinshin)
|
||||
- Norwegian
|
||||
- Knut Melvær (@kmelve)
|
||||
- Knut Melvær (@kmelve)
|
||||
- Persian (Farsi)
|
||||
- Mohammad Hossein Mojtahedi (@mhm5000)
|
||||
- Mohammad Hossein Mojtahedi (@mhm5000)
|
||||
- Polish
|
||||
- Łukasz Szeremeta (@lszeremeta)
|
||||
- Portuguese
|
||||
- Ryan O'Mullan (@RyanOM)
|
||||
- Ryan O'Mullan (@RyanOM)
|
||||
- Spanish
|
||||
- Ryan O'Mullan (@RyanOM)
|
||||
- Ryan O'Mullan (@RyanOM)
|
||||
- Simplifiled Chinese
|
||||
- Hu Hao (@howiehu)
|
||||
- Hu Hao (@howiehu)
|
||||
- Traditional Chinese
|
||||
- Hu Hao (@howiehu)
|
||||
- Hu Hao (@howiehu)
|
||||
- French
|
||||
- Samy Pessé (@SamyPesse)
|
||||
- Samy Pessé (@SamyPesse)
|
||||
- Romanian
|
||||
- Iancu Aurel (@awrelll)
|
||||
- Finnish
|
||||
- Tommi Savikko (@savikko)
|
||||
- Japanese
|
||||
- Iancu Aurel (@awrelll)
|
||||
- Korean
|
||||
- Iancu Aurel (@awrelll)
|
||||
- SangYeob Yu (@deminoth)
|
||||
- Vietnamese
|
||||
- Hong Nguyen (@nghong)
|
||||
- Hebrew
|
||||
- @a-moses
|
||||
|
||||
+64
@@ -2,6 +2,70 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 2.3.1
|
||||
- Fix black font color for ebooks (mobi, pdf and epub)
|
||||
- Fix ISO code for korean language
|
||||
- Fix korean translation
|
||||
- Fix syntax highlighting for asciidoc
|
||||
- Fix inline html escaping in markdown
|
||||
- Add warning for file outside SUMMARY
|
||||
- Force SUMMARY entries to be unique by filename
|
||||
|
||||
## 2.3.0
|
||||
- Fix nunjucks issue with multiple `{% raw %}` blocks
|
||||
- Fix crash when git conref failed
|
||||
- Fix crash when failed to download remote image (better error message)
|
||||
- Fix flicking effect when changing page (big UX improvement)
|
||||
- Add Hebrew translation (`he`)
|
||||
- Add utility method `book.config.get` for plugins
|
||||
- Hooks `page:before` and `page` are no longer deprecated
|
||||
- Remove webfonts to make website lighter
|
||||
- Make glossary's order case insensitive
|
||||
|
||||
## 2.2.0
|
||||
- Fix direction in code blocks (always LTR)
|
||||
- Add options `chapterMark` and `pageBreaksBefore` for PDF
|
||||
- Update code highlighting library
|
||||
- `book.json` accessible as `config` in templating syntax
|
||||
- Add Vietnamese translation (`vi`)
|
||||
|
||||
## 2.1.0
|
||||
- Fix error in calcul of `levels` in table of contents, error introduced a few versions ago
|
||||
- Add optional `styles/print.css` to replace `print.css` used in ebook
|
||||
|
||||
## 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,8 +2,8 @@ GitBook
|
||||
=======
|
||||
|
||||
[](http://badge.fury.io/js/gitbook)
|
||||
[](https://travis-ci.org/GitbookIO/gitbook)
|
||||
[](https://ci.appveyor.com/project/SamyPesse/gitbook)
|
||||
[](https://travis-ci.org/GitbookIO/gitbook)
|
||||
[](https://ci.appveyor.com/project/GitBook/gitbook)
|
||||
|
||||
GitBook is a command line tool (and Node.js library) for building beautiful books using GitHub/Git and Markdown (or AsciiDoc). Here is an example: [Learn Javascript](https://www.gitbook.com/book/GitBookIO/javascript).
|
||||
|
||||
@@ -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
|
||||
@@ -50,7 +50,7 @@ $ gitbook build ./repository ./outputFolder
|
||||
* [AsciiDoc Support](http://help.gitbook.com/format/asciidoc.html)
|
||||
* [Variables and Templating](http://help.gitbook.com/format/templating.html)
|
||||
* [Content References](http://help.gitbook.com/format/conrefs.html)
|
||||
* [Plugins](http://help.gitbook.com/plugins/index.html)
|
||||
* [Plugins](http://help.gitbook.com/format/plugins.html)
|
||||
* Interractive reader website:
|
||||
* Search
|
||||
* Font Settings (Serif, Sans Serif)
|
||||
|
||||
+97
-23
@@ -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) {
|
||||
@@ -475,7 +512,7 @@ Book.prototype.parsePage = function(filename, options) {
|
||||
var interpolate = function(fn) {
|
||||
return Q(fn(page))
|
||||
.then(function(_page) {
|
||||
page = _page;
|
||||
page = _page || page;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -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() {
|
||||
|
||||
+40
-5
@@ -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')
|
||||
@@ -99,8 +121,8 @@ Configuration.prototype.load = function() {
|
||||
if (!semver.satisfies(pkg.version, that.options.gitbook)) {
|
||||
throw "GitBook version doesn't satisfy version required by the book: "+that.options.gitbook;
|
||||
}
|
||||
if (that.options.gitbook == "*") {
|
||||
that.book.log.warn.ln("you should specify a gitbook version to use in your book.json, for example: "+(_.first(pkg.version.split("."))+".x.x"));
|
||||
if (that.options.gitbook != '*' && !semver.satisfies(that.options.gitbook, semver.inc(pkg.version, 'patch'))) {
|
||||
that.book.log.warn.ln("gitbook version specified in your book.json might be too strict for future patches, \""+(_.first(pkg.version.split("."))+".x.x")+"\" is more adequate");
|
||||
}
|
||||
|
||||
that.options.output = path.resolve(that.options.output || path.join(that.book.root, "_book"));
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -134,6 +156,10 @@ Configuration.prototype.normalizeLanguage = function() {
|
||||
return i18n.normalizeLanguage(this.options.language);
|
||||
};
|
||||
|
||||
// Return a configuration
|
||||
Configuration.prototype.get = function(key, def) {
|
||||
return _.get(this.options, key, def);
|
||||
};
|
||||
|
||||
// Default configuration
|
||||
Configuration.DEFAULT = {
|
||||
@@ -164,6 +190,7 @@ Configuration.DEFAULT = {
|
||||
// CSS Styles
|
||||
"styles": {
|
||||
"website": "styles/website.css",
|
||||
"print": "styles/print.css",
|
||||
"ebook": "styles/ebook.css",
|
||||
"pdf": "styles/pdf.css",
|
||||
"mobi": "styles/mobi.css",
|
||||
@@ -223,6 +250,14 @@ Configuration.DEFAULT = {
|
||||
// Choices are [u’a0’, u’a1’, u’a2’, u’a3’, u’a4’, u’a5’, u’a6’, u’b0’, u’b1’, u’b2’, u’b3’, u’b4’, u’b5’, u’b6’, u’legal’, u’letter’]
|
||||
"paperSize": "a4",
|
||||
|
||||
// How to mark detected chapters.
|
||||
// Choices are “pagebreak”, “rule”, "both" or “none”.
|
||||
"chapterMark" : "pagebreak",
|
||||
|
||||
// An XPath expression. Page breaks are inserted before the specified elements.
|
||||
// To disable use the expression: "/"
|
||||
"pageBreaksBefore": "/",
|
||||
|
||||
// Margin (in pts)
|
||||
// Note: 72 pts equals 1 inch
|
||||
"margin": {
|
||||
|
||||
@@ -18,7 +18,7 @@ var Generator = function(book, format) {
|
||||
this.namespace = "ebook";
|
||||
|
||||
// Styles to use
|
||||
this.styles = _.compact(["ebook", this.ebookFormat]);
|
||||
this.styles = _.compact(["print", "ebook", this.ebookFormat]);
|
||||
|
||||
// Convert images (svg -> png)
|
||||
this.convertImages = true;
|
||||
@@ -68,8 +68,6 @@ Generator.prototype.finish = function() {
|
||||
"--book-producer": "GitBook",
|
||||
"--publisher": "GitBook",
|
||||
"--chapter": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter ')]",
|
||||
"--chapter-mark": "pagebreak",
|
||||
"--page-breaks-before": "/",
|
||||
"--level1-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-1 ')]",
|
||||
"--level2-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-2 ')]",
|
||||
"--level3-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-3 ')]",
|
||||
@@ -82,6 +80,8 @@ Generator.prototype.finish = function() {
|
||||
var pdfOptions = that.options.pdf;
|
||||
|
||||
_.extend(_options, {
|
||||
"--chapter-mark": String(pdfOptions.chapterMark),
|
||||
"--page-breaks-before": String(pdfOptions.pageBreaksBefore),
|
||||
"--margin-left": String(pdfOptions.margin.left),
|
||||
"--margin-right": String(pdfOptions.margin.right),
|
||||
"--margin-top": String(pdfOptions.margin.top),
|
||||
|
||||
+10
-13
@@ -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");
|
||||
@@ -51,12 +50,13 @@ Generator.prototype.prepareStyles = function() {
|
||||
this.styles = _.chain(this.styles)
|
||||
.map(function(style) {
|
||||
var stylePath = that.options.styles[style];
|
||||
if (fs.existsSync(path.resolve(that.book.root, stylePath))) {
|
||||
return stylePath;
|
||||
if (stylePath && fs.existsSync(path.resolve(that.book.root, stylePath))) {
|
||||
return [style, stylePath];
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.compact()
|
||||
.object()
|
||||
.value();
|
||||
|
||||
return Q();
|
||||
@@ -79,8 +79,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 +105,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 +131,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 +238,8 @@ Generator.prototype._writeTemplate = function(tpl, options, output, interpolate)
|
||||
|
||||
basePath: ".",
|
||||
staticBase: path.join(".", "gitbook"),
|
||||
|
||||
'__': that.book.i18n.bind(that.book)
|
||||
}, options)
|
||||
);
|
||||
})
|
||||
|
||||
+1
-1
@@ -158,7 +158,7 @@ module.exports = {
|
||||
.then(function(filepath) {
|
||||
// set livereload path
|
||||
lrPath = filepath;
|
||||
console.log("Restart after change in files");
|
||||
console.log("Restart after change in file", filepath);
|
||||
console.log('');
|
||||
return generate();
|
||||
})
|
||||
|
||||
+2
-2
@@ -33,7 +33,7 @@ var Plugin = function(book, name) {
|
||||
// Type of plugins resources
|
||||
Plugin.RESOURCES = ["js", "css"];
|
||||
Plugin.HOOKS = [
|
||||
"init", "finish", "finish:before"
|
||||
"init", "finish", "finish:before", "page", "page:before"
|
||||
]
|
||||
|
||||
// Load from a name
|
||||
@@ -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() {
|
||||
|
||||
+13
-4
@@ -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");
|
||||
@@ -250,7 +250,7 @@ TemplateEngine.prototype.addBlock = function(name, block) {
|
||||
|
||||
// Extract main body and kwargs
|
||||
var body = args.pop();
|
||||
var kwargs = args.pop() || {};
|
||||
var kwargs = _.isObject(_.last(args))? args.pop() : {};
|
||||
|
||||
// Extract blocks body
|
||||
var _blocks = _.map(block.blocks, function(blockName, i){
|
||||
@@ -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) {
|
||||
@@ -316,6 +316,9 @@ TemplateEngine.prototype.renderString = function(content, context, options) {
|
||||
// Variables from book.json
|
||||
book: this.book.options.variables,
|
||||
|
||||
// Complete book.json
|
||||
config: this.book.options,
|
||||
|
||||
// infos about gitbook
|
||||
gitbook: {
|
||||
version: pkg.version,
|
||||
@@ -331,7 +334,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
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -64,6 +64,10 @@ function writeStream(filename, st) {
|
||||
d.reject(err);
|
||||
});
|
||||
|
||||
st.on('error', function(err) {
|
||||
d.reject(err);
|
||||
});
|
||||
|
||||
st.pipe(wstream);
|
||||
|
||||
return d.promise;
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ function cloneGitRepo(host, ref) {
|
||||
return exec("git clone "+host+" "+repoPath)
|
||||
.then(function() {
|
||||
return exec("git checkout "+ref, { cwd: repoPath });
|
||||
})
|
||||
});
|
||||
})
|
||||
.thenResolve(repoPath);
|
||||
});
|
||||
|
||||
+40
-32
@@ -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
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
@@ -59,6 +59,7 @@ function navigation(summary, files) {
|
||||
return [current.path, {
|
||||
index: i,
|
||||
title: current.title,
|
||||
introduction: current.introduction,
|
||||
prev: prev,
|
||||
next: next,
|
||||
level: current.level,
|
||||
|
||||
+57
-4
@@ -11,6 +11,9 @@ var links = require('./links');
|
||||
var imgUtils = require('./images');
|
||||
var fs = require('./fs');
|
||||
var batch = require('./batch');
|
||||
var code = require('./code');
|
||||
|
||||
var parsableExtensions = require('gitbook-parsers').extensions;
|
||||
|
||||
// Render a cheerio dom as html
|
||||
var renderDom = function($, dom, options) {
|
||||
@@ -183,6 +186,7 @@ function normalizeHtml(src, options) {
|
||||
$(this).attr("src", src);
|
||||
});
|
||||
|
||||
// Normalize links
|
||||
$("a").each(function() {
|
||||
var href = $(this).attr("href");
|
||||
if (!href) return;
|
||||
@@ -191,14 +195,22 @@ 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
|
||||
if (options.navigation[absolutePath]) {
|
||||
absolutePath = options.book.contentLink(absolutePath);
|
||||
}
|
||||
|
||||
// If md/adoc/rst files is not in summary
|
||||
// or for ebook, signal all files that are outside the summary
|
||||
else if (_.contains(parsableExtensions, path.extname(absolutePath))
|
||||
|| _.contains(['epub', 'pdf', 'mobi'], options.book.options.generator)) {
|
||||
options.book.log.warn.ln("page", options.input, "contains an hyperlink to resource outside spine '"+href+"'");
|
||||
}
|
||||
|
||||
// Transform as absolute
|
||||
href = links.toAbsolute("/"+absolutePath, options.base, options.output)+anchor;
|
||||
} else {
|
||||
@@ -210,12 +222,47 @@ 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) {
|
||||
// Markdown
|
||||
if (cl.search("lang-") === 0) return cl.slice("lang-".length);
|
||||
|
||||
// Asciidoc
|
||||
if (cl.search("language-") === 0) return cl.slice("language-".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) {
|
||||
@@ -253,7 +300,13 @@ function convertImages(images, options) {
|
||||
if (!image.origin && !_.contains(downloaded, image.origin)) return;
|
||||
options.book.log.debug("download image", image.origin, "...");
|
||||
downloaded.push(image.origin);
|
||||
return options.book.log.debug.promise(fs.writeStream(imgin, request(image.origin)));
|
||||
return options.book.log.debug.promise(fs.writeStream(imgin, request(image.origin)))
|
||||
.fail(function(err) {
|
||||
if (!_.isError(err)) err = new Error(err);
|
||||
|
||||
err.message = 'Fail downloading '+image.origin+': '+err.message;
|
||||
throw err;
|
||||
});
|
||||
})
|
||||
|
||||
// Write svg if content
|
||||
|
||||
@@ -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)
|
||||
|
||||
+9
-7
@@ -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,19 @@ function watch(dir) {
|
||||
toWatch.push("**/*"+ext);
|
||||
});
|
||||
|
||||
var gaze = new Gaze(toWatch, {
|
||||
cwd: dir
|
||||
var watcher = chokidar.watch(toWatch, {
|
||||
cwd: dir,
|
||||
ignored: '_book/**',
|
||||
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);
|
||||
});
|
||||
|
||||
+15
-12
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gitbook",
|
||||
"version": "2.0.0-beta.5",
|
||||
"version": "2.3.1",
|
||||
"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",
|
||||
"semver": "2.2.1",
|
||||
"gitbook-parsers": "0.8.1",
|
||||
"nunjucks": "mozilla/nunjucks#b4351ec0752b102ebd02c5e2cbc2898a6e0e4839",
|
||||
"nunjucks-autoescape": "1.0.0",
|
||||
"nunjucks-filter": "1.0.0",
|
||||
"i18n": "0.5.0",
|
||||
"semver": "5.0.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.5",
|
||||
"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.8.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"
|
||||
},
|
||||
|
||||
@@ -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.length.should.be.equal(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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
# Readme
|
||||
|
||||
Default description for the book.
|
||||
@@ -0,0 +1 @@
|
||||
# Readme
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
"title": "js-config"
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
# Readme
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"title": "json-config"
|
||||
}
|
||||
@@ -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>
|
||||
@@ -0,0 +1 @@
|
||||
# Summary
|
||||
@@ -0,0 +1 @@
|
||||
Hello World
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Summary
|
||||
|
||||
* [Page](folder/PAGE.md)
|
||||
@@ -0,0 +1,3 @@
|
||||
# Page
|
||||
|
||||
Just a page in a sub-directory to test relative link to glossary.
|
||||
@@ -0,0 +1,18 @@
|
||||
# Tests for Images
|
||||
|
||||
# SVG relative image
|
||||
|
||||
|
||||
### Convert SVG to PNG
|
||||

|
||||
|
||||
### Should only convert it once
|
||||

|
||||
|
||||
### Download remote images
|
||||

|
||||
|
||||
### Remote images with same filename
|
||||

|
||||

|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Summary
|
||||
|
||||
* [Page](./folder/PAGE.md)
|
||||
@@ -0,0 +1,3 @@
|
||||
### Images from other folder
|
||||

|
||||
|
||||
|
Before Width: | Height: | Size: 730 B After Width: | Height: | Size: 730 B |
@@ -0,0 +1,3 @@
|
||||
*
|
||||
!SUMMARY.md
|
||||
!.gitignore
|
||||
@@ -0,0 +1,6 @@
|
||||
# Summary
|
||||
|
||||
* [Hello](hello.md)
|
||||
* [Hello 2](hello2.md)
|
||||
* Hello 3
|
||||
* [Hello 4](hello3/hello4.md)
|
||||
@@ -0,0 +1,4 @@
|
||||
# Language
|
||||
|
||||
* [English](en)
|
||||
* [French](fr)
|
||||
@@ -0,0 +1 @@
|
||||
# Readme
|
||||
@@ -0,0 +1 @@
|
||||
Hello
|
||||
@@ -0,0 +1 @@
|
||||
# Summary
|
||||
@@ -0,0 +1 @@
|
||||
Bonjour
|
||||
@@ -0,0 +1 @@
|
||||
# Summary
|
||||
@@ -0,0 +1 @@
|
||||
# Readme
|
||||
@@ -0,0 +1,4 @@
|
||||
# Summary
|
||||
|
||||
* [Folder1](folder1/README.md)
|
||||
* [Folder2](folder2/README.md)
|
||||
@@ -0,0 +1,3 @@
|
||||
# Folder 1
|
||||
|
||||
[Link to folder2](../folder2/README.md)
|
||||
@@ -0,0 +1 @@
|
||||
# Folder 2
|
||||
@@ -0,0 +1,3 @@
|
||||
# Readme
|
||||
|
||||
Default description for the book.
|
||||
@@ -0,0 +1 @@
|
||||
# Summary
|
||||
@@ -0,0 +1,3 @@
|
||||
body {
|
||||
color: red;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
# Page 1
|
||||
@@ -0,0 +1 @@
|
||||
# Readme
|
||||
@@ -0,0 +1,5 @@
|
||||
# Summary
|
||||
|
||||
* [Page 1](./PAGE1.md)
|
||||
* [Page 2](./folder/PAGE2.md)
|
||||
* [Don't exists](./NOTFOUND.md)
|
||||
@@ -0,0 +1 @@
|
||||
# Page 2
|
||||
+26
-8
@@ -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");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
+46
-27
@@ -1,36 +1,55 @@
|
||||
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 copy assets', function() {
|
||||
book.should.have.file("gitbook");
|
||||
book.should.have.file("gitbook/style.css");
|
||||
});
|
||||
});
|
||||
|
||||
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);
|
||||
describe('Custom styles', function() {
|
||||
var book;
|
||||
|
||||
$("img").each(function() {
|
||||
var src = $(this).attr("src");
|
||||
assert(fs.existsSync(path.resolve(pageFolder, src)), src+" not found for page "+pageName);
|
||||
})
|
||||
before(function() {
|
||||
return books.generate("style-print", "ebook")
|
||||
.then(function(_book) {
|
||||
book = _book;
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove default print.css', function() {
|
||||
var PAGE = fs.readFileSync(
|
||||
path.join(book.options.output, "index.html"),
|
||||
{ encoding: "utf-8" }
|
||||
);
|
||||
PAGE.should.be.html({
|
||||
"link": {
|
||||
count: 1,
|
||||
attributes: {
|
||||
href: "./styles/print.css"
|
||||
}
|
||||
}
|
||||
});
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly print.css', function() {
|
||||
book.should.have.file("styles");
|
||||
book.should.have.file("styles/print.css");
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
# Glossary
|
||||
|
||||
## Description
|
||||
|
||||
This is the dexcription of a description.
|
||||
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
# Other Title
|
||||
|
||||
This is a description, it's simple, no ?
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
# Summary
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"title": "Test"
|
||||
}
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
body {
|
||||
background: red;
|
||||
}
|
||||
Vendored
-9
@@ -1,9 +0,0 @@
|
||||
|
||||
# Test
|
||||
|
||||
a test text
|
||||
|
||||
# Test 2
|
||||
|
||||
a second test
|
||||
|
||||
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
# Test
|
||||
|
||||
This file is not parsed by gitbook because the structure is defined in book.json.
|
||||
|
||||
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
# Summary
|
||||
|
||||
* [Chapter 1](test.md)
|
||||
* [Article 1](sub/test1.md)
|
||||
* [Chapter 2](test2.md)
|
||||
* [Google](https://www.google.com)
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"structure": {
|
||||
"readme": "intro.md"
|
||||
}
|
||||
}
|
||||
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
# My Book
|
||||
|
||||
Test description
|
||||
|
||||
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
# This file is used to etst links transformations:
|
||||
|
||||
This is a relative link [test](../intro.md).
|
||||
|
||||

|
||||
|
||||
This is a glossary link.
|
||||
|
||||
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
# Languages
|
||||
|
||||
* [English](en/)
|
||||
* [French](fr/)
|
||||
Vendored
-2
@@ -1,2 +0,0 @@
|
||||
# Multi-Languages test
|
||||
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
# English Book
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
# French Book
|
||||
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
= My Book
|
||||
|
||||
Test description
|
||||
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
= Summary
|
||||
|
||||
. link:test.adoc[Chapter 1]
|
||||
.. link:test1.adoc[Article 1]
|
||||
. link:test2.adoc[Chapter 2]
|
||||
Vendored
Vendored
Vendored
Vendored
-11
@@ -1,11 +0,0 @@
|
||||
# Other Title
|
||||
|
||||
A description
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
# Test with youtube videos that have the same filename:
|
||||

|
||||

|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
# Summary
|
||||
|
||||
* [Page](sub/PAGE.md)
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
title: "Test 2"
|
||||
};
|
||||
Vendored
-18
@@ -1,18 +0,0 @@
|
||||
##
|
||||
|
||||
## Image from root page
|
||||
|
||||

|
||||

|
||||
|
||||
## 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
|
||||
|
||||

|
||||
Vendored
-5
@@ -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" %}
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
Hello World
|
||||
+17
-18
@@ -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
@@ -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
@@ -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();
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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
@@ -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");
|
||||
})
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
+147
-132
@@ -1,189 +1,204 @@
|
||||
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");
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly extend template blocks with arguments', function() {
|
||||
return testTpl('{% test5args "a", "b", "c" %}{% endtest5args %}')
|
||||
.then(function(content) {
|
||||
content.should.equal("test5a,b,ctest5");
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly extend template blocks with args and kwargs', function() {
|
||||
return testTpl('{% test5kwargs "a", "b", "c", d="test", e="test2" %}{% endtest5kwargs %}')
|
||||
.then(function(content) {
|
||||
content.should.equal("test5a,b,c,d:test,e:test2,__keywords:truetest5");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -36,6 +36,21 @@ module.exports = {
|
||||
assert(blk.blocks[1].name, "finally");
|
||||
return [blk.body, blk.blocks[0].body, blk.blocks[1].body].join(blk.kwargs.separator);
|
||||
}
|
||||
}
|
||||
},
|
||||
"test5args": {
|
||||
process: function(blk) {
|
||||
return "test5"+blk.args.join(',')+"test5";
|
||||
}
|
||||
},
|
||||
"test5kwargs": {
|
||||
process: function(blk) {
|
||||
var s = blk.args.join(',');
|
||||
for (var key in blk.kwargs) {
|
||||
s = s + ','+key+':'+blk.kwargs[key];
|
||||
}
|
||||
|
||||
return "test5"+s+"test5";
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
@@ -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
@@ -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());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user