mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-26 20:27:00 +00:00
Compare commits
116 Commits
2.0.0-beta.4
...
2.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| a836bdedb4 | |||
| 15ebae8cb1 |
+12
@@ -30,6 +30,8 @@ Translators
|
||||
- Knut Melvær (@kmelve)
|
||||
- Persian (Farsi)
|
||||
- Mohammad Hossein Mojtahedi (@mhm5000)
|
||||
- Polish
|
||||
- Łukasz Szeremeta (@lszeremeta)
|
||||
- Portuguese
|
||||
- Ryan O'Mullan (@RyanOM)
|
||||
- Spanish
|
||||
@@ -40,3 +42,13 @@ Translators
|
||||
- Hu Hao (@howiehu)
|
||||
- French
|
||||
- Samy Pessé (@SamyPesse)
|
||||
- Romanian
|
||||
- Iancu Aurel (@awrelll)
|
||||
- Finnish
|
||||
- Tommi Savikko (@savikko)
|
||||
- Japanese
|
||||
- Iancu Aurel (@awrelll)
|
||||
- Korean
|
||||
- Iancu Aurel (@awrelll)
|
||||
- Vietnamese
|
||||
- Hong Nguyen (@nghong)
|
||||
+47
@@ -2,6 +2,53 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 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.0.0-beta.4
|
||||
- Fix default generator for use programmatically
|
||||
- Add option "author" for html meta tags
|
||||
|
||||
@@ -32,13 +32,13 @@ $ gitbook init
|
||||
You can serve a repository as a book using:
|
||||
|
||||
```
|
||||
$ gitbook serve ./repository
|
||||
$ gitbook serve
|
||||
```
|
||||
|
||||
Or simply build the static website using:
|
||||
|
||||
```
|
||||
$ gitbook build ./repository ./outputFolder
|
||||
$ gitbook build
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
+96
-22
@@ -2,9 +2,9 @@ var Q = require("q");
|
||||
var _ = require("lodash");
|
||||
var path = require("path");
|
||||
var util = require("util");
|
||||
var lunr = require('lunr');
|
||||
var lunr = require("lunr");
|
||||
var parsers = require("gitbook-parsers");
|
||||
var color = require('bash-color');
|
||||
var color = require("bash-color");
|
||||
|
||||
var fs = require("./utils/fs");
|
||||
var parseNavigation = require("./utils/navigation");
|
||||
@@ -12,6 +12,7 @@ var parseProgress = require("./utils/progress");
|
||||
var pageUtil = require("./utils/page");
|
||||
var batch = require("./utils/batch");
|
||||
var links = require("./utils/links");
|
||||
var i18n = require("./utils/i18n");
|
||||
var logger = require("./utils/logger");
|
||||
|
||||
var Configuration = require("./configuration");
|
||||
@@ -94,6 +95,11 @@ var Book = function(root, context, parent) {
|
||||
_.bindAll(this);
|
||||
};
|
||||
|
||||
// Return string representation
|
||||
Book.prototype.toString = function() {
|
||||
return "[Book "+this.root+"]";
|
||||
};
|
||||
|
||||
// Initialize and parse the book: config, summary, glossary
|
||||
Book.prototype.parse = function() {
|
||||
var that = this;
|
||||
@@ -109,7 +115,7 @@ Book.prototype.parse = function() {
|
||||
return that.parseLangs()
|
||||
.then(function() {
|
||||
multilingual = that.langs.length > 0;
|
||||
if (multilingual) that.log.info.ln("Parsing multilingual book, with", that.langs.length, "lanuages");
|
||||
if (multilingual) that.log.info.ln("Parsing multilingual book, with", that.langs.length, "languages");
|
||||
|
||||
// Sub-books that inherit from the current book configuration
|
||||
that.books = _.map(that.langs, function(lang) {
|
||||
@@ -229,8 +235,15 @@ Book.prototype.generate = function(generator) {
|
||||
return _.reduce(ops["content"] || [], function(prev, file, i) {
|
||||
return prev.then(function() {
|
||||
var p = ((i*100)/nFiles).toFixed(0)+"%";
|
||||
that.log.info.ln("processing", file, p);
|
||||
return Q(generator.convertFile(file));
|
||||
that.log.debug.ln("processing", file, p);
|
||||
|
||||
return Q(generator.convertFile(file))
|
||||
.fail(function(err) {
|
||||
// Transform error message to signal file
|
||||
throw that.normError(err, {
|
||||
fileName: file
|
||||
});
|
||||
});
|
||||
});
|
||||
}, Q());
|
||||
});
|
||||
@@ -364,7 +377,13 @@ Book.prototype.parseReadme = function() {
|
||||
that.log.debug.ln("readme located at", that.readmeFile);
|
||||
return that.template.renderFile(that.readmeFile)
|
||||
.then(function(content) {
|
||||
return readme.parser.readme(content);
|
||||
return readme.parser.readme(content)
|
||||
.fail(function(err) {
|
||||
throw that.normError(err, {
|
||||
name: err.name || "Readme Parse Error",
|
||||
fileName: that.readmeFile
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(function(readme) {
|
||||
@@ -391,7 +410,13 @@ Book.prototype.parseLangs = function() {
|
||||
that.log.debug.ln("languages index located at", that.langsFile);
|
||||
return that.template.renderFile(that.langsFile)
|
||||
.then(function(content) {
|
||||
return langs.parser.langs(content);
|
||||
return langs.parser.langs(content)
|
||||
.fail(function(err) {
|
||||
throw that.normError(err, {
|
||||
name: err.name || "Langs Parse Error",
|
||||
fileName: that.langsFile
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(function(langs) {
|
||||
@@ -420,8 +445,14 @@ Book.prototype.parseSummary = function() {
|
||||
.then(function(content) {
|
||||
return summary.parser.summary(content, {
|
||||
entryPoint: that.readmeFile,
|
||||
entryPointTitle: "",
|
||||
entryPointTitle: that.i18n('SUMMARY_INTRODUCTION'),
|
||||
files: that.files
|
||||
})
|
||||
.fail(function(err) {
|
||||
throw that.normError(err, {
|
||||
name: err.name || "Summary Parse Error",
|
||||
fileName: that.summaryFile
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
@@ -450,7 +481,13 @@ Book.prototype.parseGlossary = function() {
|
||||
that.log.debug.ln("glossary located at", that.glossaryFile);
|
||||
return that.template.renderFile(that.glossaryFile)
|
||||
.then(function(content) {
|
||||
return glossary.parser.glossary(content);
|
||||
return glossary.parser.glossary(content)
|
||||
.fail(function(err) {
|
||||
throw that.normError(err, {
|
||||
name: err.name || "Glossary Parse Error",
|
||||
fileName: that.glossaryFile
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(function(glossary) {
|
||||
@@ -670,8 +707,8 @@ Book.prototype.resolve = function(p) {
|
||||
return path.resolve(this.root, p);
|
||||
};
|
||||
|
||||
// Normalize a link to .html and convert README -> index
|
||||
Book.prototype.contentLink = function(link) {
|
||||
// Normalize a path to .html and convert README -> index
|
||||
Book.prototype.contentPath = function(link) {
|
||||
if (
|
||||
path.basename(link, path.extname(link)) == "README"
|
||||
|| link == this.readmeFile
|
||||
@@ -683,6 +720,11 @@ Book.prototype.contentLink = function(link) {
|
||||
return link;
|
||||
}
|
||||
|
||||
// Normalize a link to .html and convert README -> index
|
||||
Book.prototype.contentLink = function(link) {
|
||||
return links.normalize(this.contentPath(link));
|
||||
}
|
||||
|
||||
// Index a page into the search index
|
||||
Book.prototype.indexPage = function(page) {
|
||||
var nav = this.navigation[page.path];
|
||||
@@ -717,22 +759,49 @@ Book.prototype.setOutput = function(p) {
|
||||
});
|
||||
};
|
||||
|
||||
// Translate a strign according to the book language
|
||||
Book.prototype.i18n = function(phrase) {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
return i18n.__.apply({}, [this.config.normalizeLanguage()].concat(args));
|
||||
};
|
||||
|
||||
// Normalize error
|
||||
Book.prototype.normError = function(err, opts, defs) {
|
||||
if (_.isString(err)) err = new Error(err);
|
||||
|
||||
// Extend err
|
||||
_.extend(err, opts || {});
|
||||
_.defaults(err, defs || {});
|
||||
|
||||
err.lineNumber = err.lineNumber || err.lineno;
|
||||
err.columnNumber = err.columnNumber || err.colno;
|
||||
|
||||
err.toString = function() {
|
||||
var attributes = [];
|
||||
|
||||
if (this.fileName) attributes.push("In file '"+this.fileName+"'");
|
||||
if (this.lineNumber) attributes.push("Line "+this.lineNumber);
|
||||
if (this.columnNumber) attributes.push("Column "+this.columnNumber);
|
||||
return (this.name || "Error")+": "+this.message+((attributes.length > 0)? " ("+attributes.join(", ")+")" : "")
|
||||
};
|
||||
|
||||
return err;
|
||||
};
|
||||
|
||||
// Init and return a book
|
||||
Book.init = function(root) {
|
||||
var book = new Book(root);
|
||||
Book.init = function(root, opts) {
|
||||
var book = new Book(root, opts);
|
||||
var extensionToUse = ".md";
|
||||
|
||||
var chaptersPaths = function(chapters) {
|
||||
return _.reduce(chapters || [], function(accu, chapter) {
|
||||
if (!chapter.path) return accu;
|
||||
var o = {
|
||||
title: chapter.title
|
||||
};
|
||||
if (chapter.path) o.path = chapter.path;
|
||||
|
||||
return accu.concat(
|
||||
_.filter([
|
||||
{
|
||||
title: chapter.title,
|
||||
path: chapter.path
|
||||
}
|
||||
].concat(chaptersPaths(chapter.articles)))
|
||||
[o].concat(chaptersPaths(chapter.articles))
|
||||
);
|
||||
}, []);
|
||||
};
|
||||
@@ -769,12 +838,17 @@ Book.init = function(root) {
|
||||
.then(function(chapters) {
|
||||
// Create files that don't exist
|
||||
return Q.all(_.map(chapters, function(chapter) {
|
||||
if (!chapter.path) return Q();
|
||||
var absolutePath = path.resolve(book.root, chapter.path);
|
||||
|
||||
return fs.exists(absolutePath)
|
||||
.then(function(exists) {
|
||||
book.log.info.ln("create", chapter.path);
|
||||
if(exists) return;
|
||||
if(exists) {
|
||||
book.log.info.ln("found", chapter.path);
|
||||
return;
|
||||
} else {
|
||||
book.log.info.ln("create", chapter.path);
|
||||
}
|
||||
|
||||
return fs.mkdirp(path.dirname(absolutePath))
|
||||
.then(function() {
|
||||
|
||||
+34
-3
@@ -60,7 +60,6 @@ function normalizePluginsNames(plugins) {
|
||||
return _.pluck(normalizePluginsList(plugins), "name");
|
||||
};
|
||||
|
||||
|
||||
var Configuration = function(book, options) {
|
||||
var that = this;
|
||||
|
||||
@@ -75,6 +74,20 @@ var Configuration = function(book, options) {
|
||||
return that.book.root;
|
||||
}
|
||||
});
|
||||
|
||||
// options.originalInput == book.parent.root
|
||||
Object.defineProperty(this.options, "originalInput", {
|
||||
get: function () {
|
||||
return that.book.parent? that.book.parent.root : undefined;
|
||||
}
|
||||
});
|
||||
|
||||
// options.originalOutput == book.parent.options.output
|
||||
Object.defineProperty(this.options, "originalOutput", {
|
||||
get: function () {
|
||||
return that.book.parent? that.book.parent.options.output : undefined;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Read and parse the configuration
|
||||
@@ -83,8 +96,17 @@ Configuration.prototype.load = function() {
|
||||
|
||||
return Q()
|
||||
.then(function() {
|
||||
var configPath, config;
|
||||
|
||||
try {
|
||||
var _config = require(path.resolve(that.book.root, that.options.configFile));
|
||||
configPath = require.resolve(
|
||||
path.resolve(that.book.root, that.options.configFile)
|
||||
);
|
||||
|
||||
// Invalidate node.js cache for livreloading
|
||||
delete require.cache[configPath];
|
||||
|
||||
_config = require(configPath);
|
||||
that.options = _.merge(
|
||||
that.options,
|
||||
_.omit(_config, 'configFile', 'defaultsPlugins', 'generator', 'extension')
|
||||
@@ -111,7 +133,7 @@ Configuration.prototype.load = function() {
|
||||
|
||||
// Default value for text direction (from language)
|
||||
if (!that.options.direction) {
|
||||
var lang = i18n.getByLanguage(that.options.language);
|
||||
var lang = i18n.getCatalog(that.options.language);
|
||||
if (lang) that.options.direction = lang.direction;
|
||||
}
|
||||
|
||||
@@ -164,6 +186,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 +246,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
@@ -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
|
||||
};
|
||||
+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)
|
||||
@@ -57,7 +57,9 @@ function navigation(summary, files) {
|
||||
|
||||
|
||||
return [current.path, {
|
||||
index: i,
|
||||
title: current.title,
|
||||
introduction: current.introduction,
|
||||
prev: prev,
|
||||
next: next,
|
||||
level: current.level,
|
||||
|
||||
+35
-3
@@ -11,6 +11,7 @@ var links = require('./links');
|
||||
var imgUtils = require('./images');
|
||||
var fs = require('./fs');
|
||||
var batch = require('./batch');
|
||||
var code = require('./code');
|
||||
|
||||
// Render a cheerio dom as html
|
||||
var renderDom = function($, dom, options) {
|
||||
@@ -183,6 +184,7 @@ function normalizeHtml(src, options) {
|
||||
$(this).attr("src", src);
|
||||
});
|
||||
|
||||
// Normalize links
|
||||
$("a").each(function() {
|
||||
var href = $(this).attr("href");
|
||||
if (!href) return;
|
||||
@@ -191,7 +193,7 @@ function normalizeHtml(src, options) {
|
||||
// Keep it as it is
|
||||
} else if (links.isRelative(href)) {
|
||||
var parts = url.parse(href);
|
||||
var absolutePath = path.join(options.base, parts.pathname);
|
||||
var absolutePath = links.join(options.base, parts.pathname);
|
||||
var anchor = parts.hash || "";
|
||||
|
||||
// If is in navigation relative: transform as content
|
||||
@@ -210,12 +212,42 @@ function normalizeHtml(src, options) {
|
||||
$(this).attr("href", href);
|
||||
});
|
||||
|
||||
// Replace glossayr terms
|
||||
_.each(options.glossary, function(term) {
|
||||
// Highlight code blocks
|
||||
$("code").each(function() {
|
||||
// Extract language
|
||||
var lang = _.chain(
|
||||
($(this).attr("class") || "").split(" ")
|
||||
)
|
||||
.map(function(cl) {
|
||||
if (cl.search("lang-") === 0) return cl.slice("lang-".length);
|
||||
return null;
|
||||
})
|
||||
.compact()
|
||||
.first()
|
||||
.value();
|
||||
|
||||
if (lang) {
|
||||
var html = code.highlight(
|
||||
lang,
|
||||
$(this).text()
|
||||
);
|
||||
|
||||
$(this).html(html);
|
||||
}
|
||||
});
|
||||
|
||||
// Replace glossary terms
|
||||
var glossary = _.sortBy(options.glossary, function(term) {
|
||||
return -term.name.length;
|
||||
});
|
||||
_.each(glossary, function(term) {
|
||||
var r = new RegExp( "\\b(" + pregQuote(term.name.toLowerCase()) + ")\\b" , 'gi' );
|
||||
var includedInFiles = false;
|
||||
|
||||
$("*").each(function() {
|
||||
// Ignore codeblocks
|
||||
if (_.contains(["code", "pre", "a"], this.name.toLowerCase())) return;
|
||||
|
||||
replaceText($, this, r, function(match) {
|
||||
// Add to files index in glossary
|
||||
if (!includedInFiles) {
|
||||
|
||||
@@ -7,10 +7,18 @@ var calculProgress = function(navigation, current) {
|
||||
var done = true;
|
||||
|
||||
var chapters = _.chain(navigation)
|
||||
|
||||
// Transform as array
|
||||
.map(function(nav, path) {
|
||||
nav.path = path;
|
||||
return nav;
|
||||
})
|
||||
|
||||
// Sort entries
|
||||
.sortBy(function(nav) {
|
||||
return nav.index;
|
||||
})
|
||||
|
||||
.map(function(nav, i) {
|
||||
// Calcul percent
|
||||
nav.percent = (i * 100) / Math.max((n - 1), 1);
|
||||
|
||||
@@ -20,12 +20,7 @@ function optionsToShellArgs(options) {
|
||||
.join(" ");
|
||||
}
|
||||
|
||||
function escapeRegex(str) {
|
||||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
escapeRegex: escapeRegex,
|
||||
escapeShellArg: escapeShellArg,
|
||||
optionsToShellArgs: optionsToShellArgs,
|
||||
toLowerCase: String.prototype.toLowerCase.call.bind(String.prototype.toLowerCase)
|
||||
|
||||
+8
-7
@@ -1,7 +1,7 @@
|
||||
var Q = require('q');
|
||||
var _ = require('lodash');
|
||||
var path = require('path');
|
||||
var Gaze = require('gaze').Gaze;
|
||||
var chokidar = require('chokidar');
|
||||
|
||||
var parsers = require('gitbook-parsers')
|
||||
|
||||
@@ -17,17 +17,18 @@ function watch(dir) {
|
||||
toWatch.push("**/*"+ext);
|
||||
});
|
||||
|
||||
var gaze = new Gaze(toWatch, {
|
||||
cwd: dir
|
||||
var watcher = chokidar.watch(toWatch, {
|
||||
cwd: dir,
|
||||
ignoreInitial: true
|
||||
});
|
||||
|
||||
gaze.once("all", function(e, filepath) {
|
||||
gaze.close();
|
||||
watcher.once("all", function(e, filepath) {
|
||||
watcher.close();
|
||||
|
||||
d.resolve(filepath);
|
||||
});
|
||||
gaze.once("error", function(err) {
|
||||
gaze.close();
|
||||
watcher.once("error", function(err) {
|
||||
watcher.close();
|
||||
|
||||
d.reject(err);
|
||||
});
|
||||
|
||||
+14
-11
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gitbook",
|
||||
"version": "2.0.0-beta.4",
|
||||
"version": "2.2.0",
|
||||
"homepage": "https://www.gitbook.com",
|
||||
"description": "Library and cmd utility to generate GitBooks",
|
||||
"main": "lib/index.js",
|
||||
@@ -12,16 +12,16 @@
|
||||
"resolve": "0.6.3",
|
||||
"fs-extra": "0.16.5",
|
||||
"fstream-ignore": "1.0.2",
|
||||
"gitbook-parsers": "0.5.4",
|
||||
"nunjucks": "git+https://github.com/mozilla/nunjucks.git#0f8b21b8df7e8e852b2e1889388653b7075f0d09",
|
||||
"nunjucks-autoescape": "0.1.1",
|
||||
"nunjucks-filter": "0.1.0",
|
||||
"nunjucks-i18n": "1.0.0",
|
||||
"gitbook-parsers": "0.7.6",
|
||||
"nunjucks": "mozilla/nunjucks#103513c294835bcbe64222de6db494e2555e294e",
|
||||
"nunjucks-autoescape": "1.0.0",
|
||||
"nunjucks-filter": "1.0.0",
|
||||
"i18n": "0.5.0",
|
||||
"semver": "2.2.1",
|
||||
"npmi": "0.1.1",
|
||||
"cheerio": "0.18.0",
|
||||
"cheerio": "0.19.0",
|
||||
"gitbook-plugin-livereload": "0.0.1",
|
||||
"gaze": "~0.5.1",
|
||||
"chokidar": "~1.0.1",
|
||||
"send": "0.2.0",
|
||||
"tiny-lr": "0.1.5",
|
||||
"tmp": "0.0.24",
|
||||
@@ -31,10 +31,13 @@
|
||||
"request": "2.51.0",
|
||||
"npm": "2.4.1",
|
||||
"dom-serializer": "0.1.0",
|
||||
"spawn-cmd": "0.0.2"
|
||||
"spawn-cmd": "0.0.2",
|
||||
"highlight.js": "8.6.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());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+18
-33
@@ -1,40 +1,25 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var _ = require('lodash');
|
||||
var assert = require('assert');
|
||||
|
||||
var fs = require("fs");
|
||||
var fsUtil = require("../lib/utils/fs");
|
||||
describe('Website generator', function () {
|
||||
describe('Basic Book', function() {
|
||||
var book;
|
||||
|
||||
before(function() {
|
||||
return books.generate("basic", "website")
|
||||
.then(function(_book) {
|
||||
book = _book;
|
||||
});
|
||||
});
|
||||
|
||||
describe('Website Generator', function () {
|
||||
it('should correctly generate a book to website', function(done) {
|
||||
testGeneration(books[1], "website", function(output) {
|
||||
assert(fs.existsSync(path.join(output, "index.html")));
|
||||
assert(fs.existsSync(path.join(output, "search_index.json")));
|
||||
}, done);
|
||||
});
|
||||
it('should correctly output an index.html', function() {
|
||||
book.should.have.file("index.html");
|
||||
});
|
||||
|
||||
it('should correctly include styles in website', function(done) {
|
||||
testGeneration(books[0], "website", function(output) {
|
||||
assert(fs.existsSync(path.join(output, "styles/website.css")));
|
||||
|
||||
var INDEX = fs.readFileSync(path.join(output, "index.html")).toString();
|
||||
assert(INDEX.indexOf("styles/website.css") > 0);
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should correctly include glossary in website', function(done) {
|
||||
testGeneration(books[0], "website", function(output) {
|
||||
assert(fs.existsSync(path.join(output, "GLOSSARY.html")));
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should correctly generate a multilingual book to website', function(done) {
|
||||
testGeneration(books[2], "website", function(output) {
|
||||
assert(fs.existsSync(path.join(output, "index.html")));
|
||||
assert(fs.existsSync(path.join(output, "gitbook")));
|
||||
assert(fs.existsSync(path.join(output, "fr/index.html")));
|
||||
assert(fs.existsSync(path.join(output, "en/index.html")));
|
||||
}, done);
|
||||
it('should correctly copy assets', function() {
|
||||
book.should.have.file("gitbook");
|
||||
book.should.have.file("gitbook/app.js");
|
||||
book.should.have.file("gitbook/style.css");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user