mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-26 20:27:00 +00:00
Compare commits
89 Commits
2.0.0-alpha.9
...
2.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| 315556310f | |||
| 9c0b26304b | |||
| acdaea9f6c | |||
| e481deb5bb | |||
| 6d3ac6074c | |||
| 5e611bde48 | |||
| 9448562156 | |||
| e7e8fe4d08 | |||
| 8320484b88 | |||
| 0e243e6f23 | |||
| 5cd25b0d21 | |||
| 3218ee7455 | |||
| 0552007b8a | |||
| 50bc89d9d9 | |||
| 743a88f53a | |||
| ee92c6dd99 | |||
| b6c54c17d1 | |||
| 992ef1ab74 | |||
| 960848ba34 | |||
| d9aca7a9df | |||
| 05a0de2d86 | |||
| 19e4f498cf | |||
| 3055139297 | |||
| 3d6b099dea | |||
| dd970e33b8 | |||
| 59ba479465 | |||
| 54c9ecf3c2 | |||
| 8308ae69a2 | |||
| bd6c3287ed | |||
| 24fc36deb1 | |||
| 2f44b61cec | |||
| 45ee503db1 | |||
| dc826da99b | |||
| 3ea659d582 | |||
| 34fc2831e0 | |||
| 1bf68a5aa0 | |||
| d72c397f23 | |||
| 2c69525148 | |||
| ee3a0ba801 | |||
| 7a4179a2a2 | |||
| 1d0083c5f4 | |||
| 33a6111a30 | |||
| a5d7a87e31 | |||
| c7f7c5b5ab | |||
| 55a7b99b4d | |||
| 8bfba604b3 | |||
| 2a5fa1c5fb | |||
| a3e95feb26 | |||
| 145b00f590 | |||
| 5f2785f0a8 | |||
| 412529c548 | |||
| 547ec6ade8 | |||
| eac513cfa3 | |||
| 5ec8a1f18c | |||
| c923a7e01a | |||
| e1594cde2c |
@@ -0,0 +1,10 @@
|
||||
# editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
@@ -28,6 +28,8 @@ Translators
|
||||
- Andrey Akinshin (@AndreyAkinshin)
|
||||
- Norwegian
|
||||
- Knut Melvær (@kmelve)
|
||||
- Persian (Farsi)
|
||||
- Mohammad Hossein Mojtahedi (@mhm5000)
|
||||
- Portuguese
|
||||
- Ryan O'Mullan (@RyanOM)
|
||||
- Spanish
|
||||
|
||||
+29
@@ -2,6 +2,35 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 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
|
||||
- Fix links normalization (content and hash)
|
||||
|
||||
## 2.0.0-beta.3
|
||||
- Fix odd cases with code blocks escaping
|
||||
|
||||
## 2.0.0-beta.2
|
||||
- Fix definition of entry point title using SUMMARY.md
|
||||
|
||||
## 2.0.0-beta.1
|
||||
- Fix windows incompatibility
|
||||
- Add support for rtl (enabled by default for `ar` and `fa`)
|
||||
- Escape code blocks in markdown parser
|
||||
- Add Persian/Farsi translation (`fa`)
|
||||
- Add Arabic translation (`ar`)
|
||||
- Add Bengali translation (`bn`)
|
||||
- Provide generator name in template context
|
||||
|
||||
## 2.0.0-alpha.9
|
||||
- Fix links in sidebar
|
||||
- Fix normalization of html link (README to index)
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
GitBook
|
||||
=======
|
||||
|
||||
:warning: This branch contains the version 2.0.
|
||||
|
||||
[](https://travis-ci.org/GitbookIO/gitbook)
|
||||
[](http://badge.fury.io/js/gitbook)
|
||||
[](https://travis-ci.org/GitbookIO/gitbook)
|
||||
[](https://ci.appveyor.com/project/SamyPesse/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). You can publish and host book easily online using [gitbook.com](https://www.gitbook.com), a web-editor is [also available](https://www.gitbook.com/editor). You can follow [@GitBookIO](https://twitter.com/GitBookIO) on Twitter. Complete documentation is available at [help.gitbook.io](http://help.gitbook.io/).
|
||||
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).
|
||||
|
||||
You can publish and host book easily online using [gitbook.com](https://www.gitbook.com), a web-editor is [also available](https://www.gitbook.com/editor).
|
||||
|
||||
Stay updated by following [@GitBookIO](https://twitter.com/GitBookIO) on Twitter or [GitBook](https://www.facebook.com/gitbookcom) on Facebook.
|
||||
|
||||
Complete documentation is available at [help.gitbook.com](http://help.gitbook.com/).
|
||||
|
||||

|
||||
|
||||
@@ -27,25 +32,25 @@ $ 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
|
||||
|
||||
* [Output as a website or ebook (pdf, epub, mobi)](#output-formats)
|
||||
* [Multi-Languages](#multi-languages)
|
||||
* [Glossary](#glossary)
|
||||
* [Cover](#cover)
|
||||
* [AsciiDoc Support](#asciidoc)
|
||||
* [Variables and Templating](#variables-and-templating)
|
||||
* [Content References](#content-references)
|
||||
* [Plugins](#plugins)
|
||||
* [Output as a website or ebook (pdf, epub, mobi)](http://help.gitbook.com/format/output.html)
|
||||
* [Multi-Languages](http://help.gitbook.com/format/languages.html)
|
||||
* [Glossary](http://help.gitbook.com/format/glossary.html)
|
||||
* [Cover](http://help.gitbook.com/format/cover.html)
|
||||
* [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)
|
||||
* Interractive reader website:
|
||||
* Search
|
||||
* Font Settings (Serif, Sans Serif)
|
||||
@@ -199,7 +204,7 @@ The platform [GitBook.com](https://www.gitbook.com/) is like an "Heroku for book
|
||||
|
||||
Plugins can be used to extend your book's functionality. Read [GitbookIO/plugin](https://github.com/GitbookIO/plugin) for more information about how to build a plugin for GitBook.
|
||||
|
||||
Plugins needed to build a book can be installed using: `gitbook install ./`. You can find plugins at [plugins.gitbook.com](plugins.gitbook.com).
|
||||
Plugins needed to build a book can be installed using: `gitbook install ./`. You can find plugins at [plugins.gitbook.com](http://plugins.gitbook.com).
|
||||
|
||||
|
||||
## Debugging
|
||||
@@ -209,3 +214,16 @@ You can use the options `--log=debug` and `--debug` to get better error messages
|
||||
```
|
||||
$ gitbook build ./ -- log=debug --debug
|
||||
```
|
||||
|
||||
#### How to use the latest commit from GitBook in gitbook-cli
|
||||
|
||||
To use the latest commit from `GitBook/gitbook` with `gitbook-cli`:
|
||||
|
||||
```
|
||||
$ git clone https://github.com/GitbookIO/gitbook.git ./gitbook
|
||||
$ gitbook versions:link 2.0.0 ./gitbook
|
||||
```
|
||||
|
||||
Now the version tag `2.0.0` wil be associated with the `./gitbook` folder.
|
||||
|
||||
You can uninstall it using: `gitbook versions:uninstall 2.0.0`.
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# Fix line endings in Windows. (runs before repo cloning)
|
||||
init:
|
||||
- git config --global core.autocrlf input
|
||||
|
||||
# Test against these versions of Node.js.
|
||||
environment:
|
||||
matrix:
|
||||
- nodejs_version: "0.10"
|
||||
- nodejs_version: "0.11"
|
||||
|
||||
# Install scripts. (runs after repo cloning)
|
||||
install:
|
||||
# Get the latest stable version of Node.js or io.js
|
||||
- ps: Install-Product node $env:nodejs_version
|
||||
# install svgexport
|
||||
- npm install svgexport -g
|
||||
# install modules
|
||||
- npm install
|
||||
|
||||
# Post-install test scripts.
|
||||
test_script:
|
||||
# Output useful info for debugging.
|
||||
- node --version
|
||||
- npm --version
|
||||
# run tests
|
||||
- npm test
|
||||
|
||||
# Don't actually build.
|
||||
build: off
|
||||
+1
-1
@@ -3,5 +3,5 @@
|
||||
var color = require('bash-color');
|
||||
|
||||
console.log(color.red("You need to install 'gitbook-cli' to have access to the gitbook command anywhere on your system."));
|
||||
console.log(color.red("If you've installe this package globally, you need to uninstall it."));
|
||||
console.log(color.red("If you've installed this package globally, you need to uninstall it."));
|
||||
console.log(color.red(">> Run 'npm uninstall -g gitbook' then 'npm install -g gitbook-cli'"));
|
||||
|
||||
+331
-317
@@ -22,68 +22,68 @@ var PluginsList = require("./pluginslist");
|
||||
var generators = require("./generators");
|
||||
|
||||
var Book = function(root, context, parent) {
|
||||
var that = this;
|
||||
var that = this;
|
||||
|
||||
this.context = _.defaults(context || {}, {
|
||||
// Extend book configuration
|
||||
config: {},
|
||||
this.context = _.defaults(context || {}, {
|
||||
// Extend book configuration
|
||||
config: {},
|
||||
|
||||
// Log function
|
||||
log: function(msg) {
|
||||
process.stdout.write(msg);
|
||||
},
|
||||
// Log function
|
||||
log: function(msg) {
|
||||
process.stdout.write(msg);
|
||||
},
|
||||
|
||||
// Log level
|
||||
logLevel: "info"
|
||||
});
|
||||
// Log level
|
||||
logLevel: "info"
|
||||
});
|
||||
|
||||
// Log
|
||||
this.log = logger(this.context.log, this.context.logLevel);
|
||||
// Log
|
||||
this.log = logger(this.context.log, this.context.logLevel);
|
||||
|
||||
// Root folder of the book
|
||||
this.root = path.resolve(root);
|
||||
// Root folder of the book
|
||||
this.root = path.resolve(root);
|
||||
|
||||
// Parent book
|
||||
this.parent = parent;
|
||||
// Parent book
|
||||
this.parent = parent;
|
||||
|
||||
// Configuration
|
||||
this.config = new Configuration(this, this.context.config);
|
||||
Object.defineProperty(this, "options", {
|
||||
get: function () {
|
||||
return this.config.options;
|
||||
}
|
||||
});
|
||||
// Configuration
|
||||
this.config = new Configuration(this, this.context.config);
|
||||
Object.defineProperty(this, "options", {
|
||||
get: function () {
|
||||
return this.config.options;
|
||||
}
|
||||
});
|
||||
|
||||
// Template
|
||||
this.template = new TemplateEngine(this);
|
||||
// Template
|
||||
this.template = new TemplateEngine(this);
|
||||
|
||||
// Summary
|
||||
this.summary = {};
|
||||
this.navigation = [];
|
||||
// Summary
|
||||
this.summary = {};
|
||||
this.navigation = [];
|
||||
|
||||
// Glossary
|
||||
this.glossary = [];
|
||||
// Glossary
|
||||
this.glossary = [];
|
||||
|
||||
// Langs
|
||||
this.langs = [];
|
||||
// Langs
|
||||
this.langs = [];
|
||||
|
||||
// Sub-books
|
||||
this.books = [];
|
||||
// Sub-books
|
||||
this.books = [];
|
||||
|
||||
// Files in the book
|
||||
this.files = [];
|
||||
// Files in the book
|
||||
this.files = [];
|
||||
|
||||
// List of plugins
|
||||
this.plugins = new PluginsList(this);
|
||||
// List of plugins
|
||||
this.plugins = new PluginsList(this);
|
||||
|
||||
// Structure files
|
||||
// Structure files
|
||||
this.summaryFile = null;
|
||||
this.glossaryFile = null;
|
||||
this.readmeFile = null;
|
||||
this.readmeFile = null;
|
||||
this.langsFile = null;
|
||||
|
||||
// Search Index
|
||||
this.searchIndex = lunr(function () {
|
||||
// Search Index
|
||||
this.searchIndex = lunr(function () {
|
||||
this.ref('url');
|
||||
|
||||
this.field('title', { boost: 10 });
|
||||
@@ -91,153 +91,158 @@ var Book = function(root, context, parent) {
|
||||
});
|
||||
|
||||
// Bind methods
|
||||
_.bindAll(this);
|
||||
_.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;
|
||||
var multilingual = false;
|
||||
var that = this;
|
||||
var multilingual = false;
|
||||
|
||||
return this.parseConfig()
|
||||
return this.parseConfig()
|
||||
|
||||
.then(function() {
|
||||
return that.parsePlugins();
|
||||
})
|
||||
.then(function() {
|
||||
return that.parsePlugins();
|
||||
})
|
||||
|
||||
.then(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");
|
||||
.then(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");
|
||||
|
||||
// Sub-books that inherit from the current book configuration
|
||||
that.books = _.map(that.langs, function(lang) {
|
||||
that.log.info.ln("Preparing language book", lang.lang);
|
||||
return new Book(
|
||||
path.join(that.root, lang.path),
|
||||
_.merge({}, that.context, {
|
||||
config: _.extend({}, that.options, {
|
||||
'output': path.join(that.options.output, lang.lang),
|
||||
'language': lang.lang
|
||||
})
|
||||
}),
|
||||
that
|
||||
)
|
||||
});
|
||||
});
|
||||
})
|
||||
// Sub-books that inherit from the current book configuration
|
||||
that.books = _.map(that.langs, function(lang) {
|
||||
that.log.info.ln("Preparing language book", lang.lang);
|
||||
return new Book(
|
||||
path.join(that.root, lang.path),
|
||||
_.merge({}, that.context, {
|
||||
config: _.extend({}, that.options, {
|
||||
'output': path.join(that.options.output, lang.lang),
|
||||
'language': lang.lang
|
||||
})
|
||||
}),
|
||||
that
|
||||
)
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
.then(function() {
|
||||
if (multilingual) return;
|
||||
return that.listAllFiles();
|
||||
})
|
||||
.then(function() {
|
||||
if (multilingual) return;
|
||||
return that.parseReadme();
|
||||
})
|
||||
.then(function() {
|
||||
if (multilingual) return;
|
||||
return that.parseSummary();
|
||||
})
|
||||
.then(function() {
|
||||
if (multilingual) return;
|
||||
return that.parseGlossary();
|
||||
})
|
||||
.then(function() {
|
||||
if (multilingual) return;
|
||||
return that.listAllFiles();
|
||||
})
|
||||
.then(function() {
|
||||
if (multilingual) return;
|
||||
return that.parseReadme();
|
||||
})
|
||||
.then(function() {
|
||||
if (multilingual) return;
|
||||
return that.parseSummary();
|
||||
})
|
||||
.then(function() {
|
||||
if (multilingual) return;
|
||||
return that.parseGlossary();
|
||||
})
|
||||
|
||||
.then(function() {
|
||||
// Init sub-books
|
||||
return _.reduce(that.books, function(prev, book) {
|
||||
return prev.then(function() {
|
||||
return book.parse();
|
||||
});
|
||||
}, Q());
|
||||
})
|
||||
.then(function() {
|
||||
// Init sub-books
|
||||
return _.reduce(that.books, function(prev, book) {
|
||||
return prev.then(function() {
|
||||
return book.parse();
|
||||
});
|
||||
}, Q());
|
||||
})
|
||||
|
||||
.thenResolve(this);
|
||||
.thenResolve(this);
|
||||
};
|
||||
|
||||
// Generate the output
|
||||
Book.prototype.generate = function(generator) {
|
||||
var that = this;
|
||||
that.options.generator = generator || that.options.generator;
|
||||
var that = this;
|
||||
that.options.generator = generator || that.options.generator;
|
||||
|
||||
that.log.info.ln("start generation with", that.options.generator, "generator");
|
||||
return Q()
|
||||
that.log.info.ln("start generation with", that.options.generator, "generator");
|
||||
return Q()
|
||||
|
||||
// Clean output folder
|
||||
.then(function() {
|
||||
// Clean output folder
|
||||
.then(function() {
|
||||
that.log.info("clean", that.options.generator, "generator");
|
||||
return fs.clean(that.options.output)
|
||||
return fs.clean(that.options.output)
|
||||
.progress(function(p) {
|
||||
that.log.debug.ln("remove", p.file, "("+p.i+"/"+p.count+")");
|
||||
})
|
||||
.then(function() {
|
||||
that.log.info.ok();
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
// Create generator
|
||||
.then(function() {
|
||||
var Generator = generators[generator];
|
||||
if (!Generator) throw "Generator '"+that.options.generator+"' doesn't exist";
|
||||
generator = new Generator(that);
|
||||
// Create generator
|
||||
.then(function() {
|
||||
var Generator = generators[generator];
|
||||
if (!Generator) throw "Generator '"+that.options.generator+"' doesn't exist";
|
||||
generator = new Generator(that);
|
||||
|
||||
return generator.prepare();
|
||||
})
|
||||
return generator.prepare();
|
||||
})
|
||||
|
||||
// Generate content
|
||||
.then(function() {
|
||||
if (that.isMultilingual()) {
|
||||
return that.generateMultiLingual(generator);
|
||||
} else {
|
||||
// Separate list of files into the different operations needed
|
||||
var ops = _.groupBy(that.files, function(file) {
|
||||
if (file[file.length -1] == "/") {
|
||||
return "directories";
|
||||
// Generate content
|
||||
.then(function() {
|
||||
if (that.isMultilingual()) {
|
||||
return that.generateMultiLingual(generator);
|
||||
} else {
|
||||
// Separate list of files into the different operations needed
|
||||
var ops = _.groupBy(that.files, function(file) {
|
||||
if (file[file.length -1] == "/") {
|
||||
return "directories";
|
||||
} else if (_.contains(parsers.extensions, path.extname(file)) && that.navigation[file]) {
|
||||
return "content";
|
||||
return "content";
|
||||
} else {
|
||||
return "files";
|
||||
return "files";
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
return Q()
|
||||
return Q()
|
||||
|
||||
// First, let's create folder
|
||||
.then(function() {
|
||||
return _.reduce(ops["directories"] || [], function(prev, folder) {
|
||||
return prev.then(function() {
|
||||
that.log.debug.ln("transferring folder", folder);
|
||||
return Q(generator.transferFolder(folder));
|
||||
});
|
||||
}, Q());
|
||||
})
|
||||
// First, let's create folder
|
||||
.then(function() {
|
||||
return _.reduce(ops["directories"] || [], function(prev, folder) {
|
||||
return prev.then(function() {
|
||||
that.log.debug.ln("transferring folder", folder);
|
||||
return Q(generator.transferFolder(folder));
|
||||
});
|
||||
}, Q());
|
||||
})
|
||||
|
||||
// Then, let's copy other files
|
||||
.then(function() {
|
||||
return Q.all(_.map(ops["files"] || [], function(file) {
|
||||
that.log.debug.ln("transferring file", file);
|
||||
// Then, let's copy other files
|
||||
.then(function() {
|
||||
return Q.all(_.map(ops["files"] || [], function(file) {
|
||||
that.log.debug.ln("transferring file", file);
|
||||
return Q(generator.transferFile(file));
|
||||
}));
|
||||
})
|
||||
}));
|
||||
})
|
||||
|
||||
// Finally let's generate content
|
||||
.then(function() {
|
||||
// Finally let's generate content
|
||||
.then(function() {
|
||||
var nFiles = (ops["content"] || []).length;
|
||||
return _.reduce(ops["content"] || [], function(prev, file, i) {
|
||||
return prev.then(function() {
|
||||
return prev.then(function() {
|
||||
var p = ((i*100)/nFiles).toFixed(0)+"%";
|
||||
that.log.info.ln("processing", file, p);
|
||||
return Q(generator.convertFile(file));
|
||||
});
|
||||
}, Q());
|
||||
});
|
||||
}
|
||||
})
|
||||
that.log.info.ln("processing", file, p);
|
||||
return Q(generator.convertFile(file));
|
||||
});
|
||||
}, Q());
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
// Finish generation
|
||||
// Finish generation
|
||||
.then(function() {
|
||||
return generator.callHook("finish:before");
|
||||
})
|
||||
@@ -248,28 +253,28 @@ Book.prototype.generate = function(generator) {
|
||||
return generator.callHook("finish");
|
||||
})
|
||||
.then(function() {
|
||||
that.log.info.ln("generation is finished");
|
||||
that.log.info.ln("generation is finished");
|
||||
});
|
||||
};
|
||||
|
||||
// Generate the output for a multilingual book
|
||||
Book.prototype.generateMultiLingual = function(generator) {
|
||||
var that = this;
|
||||
var that = this;
|
||||
|
||||
return Q()
|
||||
.then(function() {
|
||||
// Generate sub-books
|
||||
return _.reduce(that.books, function(prev, book) {
|
||||
return prev.then(function() {
|
||||
return book.generate(that.options.generator);
|
||||
});
|
||||
}, Q());
|
||||
});
|
||||
return Q()
|
||||
.then(function() {
|
||||
// Generate sub-books
|
||||
return _.reduce(that.books, function(prev, book) {
|
||||
return prev.then(function() {
|
||||
return book.generate(that.options.generator);
|
||||
});
|
||||
}, Q());
|
||||
});
|
||||
};
|
||||
|
||||
// Extract files from ebook generated
|
||||
Book.prototype.generateFile = function(output, options) {
|
||||
var book = this;
|
||||
var book = this;
|
||||
|
||||
options = _.defaults(options || {}, {
|
||||
ebookFormat: path.extname(output).slice(1)
|
||||
@@ -278,7 +283,7 @@ Book.prototype.generateFile = function(output, options) {
|
||||
|
||||
return fs.tmp.dir()
|
||||
.then(function(tmpDir) {
|
||||
book.setOutput(tmpDir);
|
||||
book.setOutput(tmpDir);
|
||||
|
||||
return book.generate(options.ebookFormat)
|
||||
.then(function(_options) {
|
||||
@@ -313,7 +318,7 @@ Book.prototype.generateFile = function(output, options) {
|
||||
}
|
||||
})
|
||||
.then(function(n) {
|
||||
book.log.info.ok(n+" file(s) generated");
|
||||
book.log.info.ok(n+" file(s) generated");
|
||||
|
||||
return fs.remove(tmpDir);
|
||||
});
|
||||
@@ -323,146 +328,147 @@ Book.prototype.generateFile = function(output, options) {
|
||||
|
||||
// Parse configuration
|
||||
Book.prototype.parseConfig = function() {
|
||||
var that = this;
|
||||
var that = this;
|
||||
|
||||
that.log.info("loading book configuration....")
|
||||
return that.config.load()
|
||||
.then(function() {
|
||||
that.log.info.ok();
|
||||
});
|
||||
that.log.info("loading book configuration....")
|
||||
return that.config.load()
|
||||
.then(function() {
|
||||
that.log.info.ok();
|
||||
});
|
||||
};
|
||||
|
||||
// Parse list of plugins
|
||||
Book.prototype.parsePlugins = function() {
|
||||
var that = this;
|
||||
var failed = [];
|
||||
var that = this;
|
||||
var failed = [];
|
||||
|
||||
// Load plugins
|
||||
return that.plugins.load(that.options.plugins)
|
||||
.then(function() {
|
||||
if (_.size(that.plugins.failed) > 0) return Q.reject(new Error("Error loading plugins: "+that.plugins.failed.join(",")+". Run 'gitbook install' to install plugins from NPM."));
|
||||
if (_.size(that.plugins.failed) > 0) return Q.reject(new Error("Error loading plugins: "+that.plugins.failed.join(",")+". Run 'gitbook install' to install plugins from NPM."));
|
||||
|
||||
that.log.info.ok(that.plugins.count()+" plugins loaded");
|
||||
that.log.debug.ln("normalize plugins list");
|
||||
that.log.info.ok(that.plugins.count()+" plugins loaded");
|
||||
that.log.debug.ln("normalize plugins list");
|
||||
});
|
||||
};
|
||||
|
||||
// Parse readme to extract defaults title and description
|
||||
Book.prototype.parseReadme = function() {
|
||||
var that = this;
|
||||
var structure = that.config.getStructure("readme");
|
||||
that.log.debug.ln("start parsing readme:", structure);
|
||||
var that = this;
|
||||
var structure = that.config.getStructure("readme");
|
||||
that.log.debug.ln("start parsing readme:", structure);
|
||||
|
||||
return that.findFile(structure)
|
||||
.then(function(readme) {
|
||||
if (!readme) throw "No README file";
|
||||
if (!_.contains(that.files, readme.path)) throw "README file is ignored";
|
||||
return that.findFile(structure)
|
||||
.then(function(readme) {
|
||||
if (!readme) throw "No README file";
|
||||
if (!_.contains(that.files, readme.path)) throw "README file is ignored";
|
||||
|
||||
that.readmeFile = readme.path;
|
||||
that.readmeFile = readme.path;
|
||||
that._defaultsStructure(that.readmeFile);
|
||||
|
||||
that.log.debug.ln("readme located at", that.readmeFile);
|
||||
return that.template.renderFile(that.readmeFile)
|
||||
.then(function(content) {
|
||||
return readme.parser.readme(content);
|
||||
});
|
||||
})
|
||||
.then(function(readme) {
|
||||
that.options.title = that.options.title || readme.title;
|
||||
that.options.description = that.options.description || readme.description;
|
||||
});
|
||||
that.log.debug.ln("readme located at", that.readmeFile);
|
||||
return that.template.renderFile(that.readmeFile)
|
||||
.then(function(content) {
|
||||
return readme.parser.readme(content);
|
||||
});
|
||||
})
|
||||
.then(function(readme) {
|
||||
that.options.title = that.options.title || readme.title;
|
||||
that.options.description = that.options.description || readme.description;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Parse langs to extract list of sub-books
|
||||
Book.prototype.parseLangs = function() {
|
||||
var that = this;
|
||||
var that = this;
|
||||
|
||||
var structure = that.config.getStructure("langs");
|
||||
that.log.debug.ln("start parsing languages index:", structure);
|
||||
var structure = that.config.getStructure("langs");
|
||||
that.log.debug.ln("start parsing languages index:", structure);
|
||||
|
||||
return that.findFile(structure)
|
||||
.then(function(langs) {
|
||||
if (!langs) return [];
|
||||
return that.findFile(structure)
|
||||
.then(function(langs) {
|
||||
if (!langs) return [];
|
||||
|
||||
that.langsFile = langs.path;
|
||||
that._defaultsStructure(that.langsFile);
|
||||
|
||||
that.log.debug.ln("languages index located at", that.langsFile);
|
||||
return that.template.renderFile(that.langsFile)
|
||||
.then(function(content) {
|
||||
return langs.parser.langs(content);
|
||||
});
|
||||
})
|
||||
.then(function(langs) {
|
||||
that.langs = langs;
|
||||
});
|
||||
that.log.debug.ln("languages index located at", that.langsFile);
|
||||
return that.template.renderFile(that.langsFile)
|
||||
.then(function(content) {
|
||||
return langs.parser.langs(content);
|
||||
});
|
||||
})
|
||||
.then(function(langs) {
|
||||
that.langs = langs;
|
||||
});
|
||||
};
|
||||
|
||||
// Parse summary to extract list of chapters
|
||||
Book.prototype.parseSummary = function() {
|
||||
var that = this;
|
||||
var that = this;
|
||||
|
||||
var structure = that.config.getStructure("summary");
|
||||
that.log.debug.ln("start parsing summary:", structure);
|
||||
var structure = that.config.getStructure("summary");
|
||||
that.log.debug.ln("start parsing summary:", structure);
|
||||
|
||||
return that.findFile(structure)
|
||||
.then(function(summary) {
|
||||
if (!summary) throw "No SUMMARY file";
|
||||
return that.findFile(structure)
|
||||
.then(function(summary) {
|
||||
if (!summary) throw "No SUMMARY file";
|
||||
|
||||
// Remove the summary from the list of files to parse
|
||||
// Remove the summary from the list of files to parse
|
||||
that.summaryFile = summary.path;
|
||||
that._defaultsStructure(that.summaryFile);
|
||||
that.files = _.without(that.files, that.summaryFile);
|
||||
that.files = _.without(that.files, that.summaryFile);
|
||||
|
||||
that.log.debug.ln("summary located at", that.summaryFile);
|
||||
return that.template.renderFile(that.summaryFile)
|
||||
.then(function(content) {
|
||||
return summary.parser.summary(content, {
|
||||
entryPoint: that.readmeFile,
|
||||
files: that.files
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(function(summary) {
|
||||
that.summary = summary;
|
||||
that.navigation = parseNavigation(that.summary, that.files);
|
||||
});
|
||||
that.log.debug.ln("summary located at", that.summaryFile);
|
||||
return that.template.renderFile(that.summaryFile)
|
||||
.then(function(content) {
|
||||
return summary.parser.summary(content, {
|
||||
entryPoint: that.readmeFile,
|
||||
entryPointTitle: "",
|
||||
files: that.files
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(function(summary) {
|
||||
that.summary = summary;
|
||||
that.navigation = parseNavigation(that.summary, that.files);
|
||||
});
|
||||
};
|
||||
|
||||
// Parse glossary to extract terms
|
||||
Book.prototype.parseGlossary = function() {
|
||||
var that = this;
|
||||
var that = this;
|
||||
|
||||
var structure = that.config.getStructure("glossary");
|
||||
that.log.debug.ln("start parsing glossary: ", structure);
|
||||
var structure = that.config.getStructure("glossary");
|
||||
that.log.debug.ln("start parsing glossary: ", structure);
|
||||
|
||||
return that.findFile(structure)
|
||||
.then(function(glossary) {
|
||||
if (!glossary) return [];
|
||||
return that.findFile(structure)
|
||||
.then(function(glossary) {
|
||||
if (!glossary) return [];
|
||||
|
||||
// Remove the glossary from the list of files to parse
|
||||
// Remove the glossary from the list of files to parse
|
||||
that.glossaryFile = glossary.path;
|
||||
that._defaultsStructure(that.glossaryFile);
|
||||
that.files = _.without(that.files, that.glossaryFile);
|
||||
that.files = _.without(that.files, that.glossaryFile);
|
||||
|
||||
that.log.debug.ln("glossary located at", that.glossaryFile);
|
||||
return that.template.renderFile(that.glossaryFile)
|
||||
.then(function(content) {
|
||||
return glossary.parser.glossary(content);
|
||||
});
|
||||
})
|
||||
.then(function(glossary) {
|
||||
that.glossary = glossary;
|
||||
});
|
||||
that.log.debug.ln("glossary located at", that.glossaryFile);
|
||||
return that.template.renderFile(that.glossaryFile)
|
||||
.then(function(content) {
|
||||
return glossary.parser.glossary(content);
|
||||
});
|
||||
})
|
||||
.then(function(glossary) {
|
||||
that.glossary = glossary;
|
||||
});
|
||||
};
|
||||
|
||||
// Parse a page
|
||||
Book.prototype.parsePage = function(filename, options) {
|
||||
var that = this, page = {};
|
||||
var that = this, page = {};
|
||||
options = _.defaults(options || {}, {
|
||||
// Transform svg images
|
||||
convertImages: false,
|
||||
// Transform svg images
|
||||
convertImages: false,
|
||||
|
||||
// Interpolate before templating
|
||||
interpolateTemplate: _.identity,
|
||||
@@ -478,12 +484,12 @@ Book.prototype.parsePage = function(filename, options) {
|
||||
});
|
||||
};
|
||||
|
||||
that.log.debug.ln("start parsing file", filename);
|
||||
that.log.debug.ln("start parsing file", filename);
|
||||
|
||||
var extension = path.extname(filename);
|
||||
var filetype = parsers.get(extension);
|
||||
var extension = path.extname(filename);
|
||||
var filetype = parsers.get(extension);
|
||||
|
||||
if (!filetype) return Q.reject(new Error("Can't parse file: "+filename));
|
||||
if (!filetype) return Q.reject(new Error("Can't parse file: "+filename));
|
||||
|
||||
// Type of parser used
|
||||
page.type = filetype.name;
|
||||
@@ -497,7 +503,7 @@ Book.prototype.parsePage = function(filename, options) {
|
||||
// Progress in the book
|
||||
page.progress = parseProgress(that.navigation, filename);
|
||||
|
||||
that.log.debug.ln("render template", filename);
|
||||
that.log.debug.ln("render template", filename);
|
||||
|
||||
// Read file content
|
||||
return that.readFile(page.path)
|
||||
@@ -507,12 +513,20 @@ Book.prototype.parsePage = function(filename, options) {
|
||||
return interpolate(options.interpolateTemplate);
|
||||
})
|
||||
|
||||
// Prepare page markup
|
||||
.then(function() {
|
||||
return filetype.page.prepare(page.content)
|
||||
.then(function(content) {
|
||||
page.content = content;
|
||||
});
|
||||
})
|
||||
|
||||
// Generate template
|
||||
.then(function() {
|
||||
return that.template.renderPage(page);
|
||||
})
|
||||
|
||||
// Parse markup
|
||||
// Prepare and Parse markup
|
||||
.then(function(content) {
|
||||
page.content = content;
|
||||
|
||||
@@ -522,88 +536,88 @@ Book.prototype.parsePage = function(filename, options) {
|
||||
|
||||
// Post process sections
|
||||
.then(function(_page) {
|
||||
return _.reduce(_page.sections, function(prev, section) {
|
||||
return prev.then(function(_sections) {
|
||||
return that.template.postProcess(section.content || "")
|
||||
.then(function(content) {
|
||||
section.content = content;
|
||||
return _sections.concat([section]);
|
||||
})
|
||||
});
|
||||
}, Q([]));
|
||||
return _.reduce(_page.sections, function(prev, section) {
|
||||
return prev.then(function(_sections) {
|
||||
return that.template.postProcess(section.content || "")
|
||||
.then(function(content) {
|
||||
section.content = content;
|
||||
return _sections.concat([section]);
|
||||
})
|
||||
});
|
||||
}, Q([]));
|
||||
})
|
||||
|
||||
// Prepare html
|
||||
.then(function(_sections) {
|
||||
return pageUtil.normalize(_sections, {
|
||||
book: that,
|
||||
convertImages: options.convertImages,
|
||||
input: filename,
|
||||
.then(function(_sections) {
|
||||
return pageUtil.normalize(_sections, {
|
||||
book: that,
|
||||
convertImages: options.convertImages,
|
||||
input: filename,
|
||||
navigation: that.navigation,
|
||||
base: path.dirname(filename) || './',
|
||||
output: path.dirname(filename) || './',
|
||||
glossary: that.glossary
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
// Interpolate output
|
||||
.then(function(_sections) {
|
||||
page.sections = _sections;
|
||||
return interpolate(options.interpolateContent);
|
||||
})
|
||||
// Interpolate output
|
||||
.then(function(_sections) {
|
||||
page.sections = _sections;
|
||||
return interpolate(options.interpolateContent);
|
||||
})
|
||||
|
||||
.then(function() {
|
||||
that.indexPage(page);
|
||||
return page;
|
||||
});
|
||||
.then(function() {
|
||||
that.indexPage(page);
|
||||
return page;
|
||||
});
|
||||
};
|
||||
|
||||
// Find file that can be parsed with a specific filename
|
||||
Book.prototype.findFile = function(filename) {
|
||||
var that = this;
|
||||
var that = this;
|
||||
|
||||
return _.reduce(parsers.extensions, function(prev, ext) {
|
||||
return prev.then(function(output) {
|
||||
// Stop if already find a parser
|
||||
if (output) return output;
|
||||
return _.reduce(parsers.extensions, function(prev, ext) {
|
||||
return prev.then(function(output) {
|
||||
// Stop if already find a parser
|
||||
if (output) return output;
|
||||
|
||||
var filepath = filename+ext;
|
||||
var filepath = filename+ext;
|
||||
|
||||
return that.fileExists(filepath)
|
||||
.then(function(exists) {
|
||||
if (!exists) return null;
|
||||
return {
|
||||
parser: parsers.get(ext),
|
||||
path: filepath
|
||||
};
|
||||
})
|
||||
});
|
||||
}, Q(null));
|
||||
return that.fileExists(filepath)
|
||||
.then(function(exists) {
|
||||
if (!exists) return null;
|
||||
return {
|
||||
parser: parsers.get(ext),
|
||||
path: filepath
|
||||
};
|
||||
})
|
||||
});
|
||||
}, Q(null));
|
||||
};
|
||||
|
||||
// Check if a file exists in the book
|
||||
Book.prototype.fileExists = function(filename) {
|
||||
return fs.exists(
|
||||
path.join(this.root, filename)
|
||||
);
|
||||
return fs.exists(
|
||||
path.join(this.root, filename)
|
||||
);
|
||||
};
|
||||
|
||||
// Read a file
|
||||
Book.prototype.readFile = function(filename) {
|
||||
return fs.readFile(
|
||||
path.join(this.root, filename),
|
||||
{ encoding: "utf8" }
|
||||
);
|
||||
return fs.readFile(
|
||||
path.join(this.root, filename),
|
||||
{ encoding: "utf8" }
|
||||
);
|
||||
};
|
||||
|
||||
// Return stat for a file
|
||||
Book.prototype.statFile = function(filename) {
|
||||
return fs.stat(path.join(this.root, filename));
|
||||
return fs.stat(path.join(this.root, filename));
|
||||
};
|
||||
|
||||
// List all files in the book
|
||||
Book.prototype.listAllFiles = function() {
|
||||
var that = this;
|
||||
var that = this;
|
||||
|
||||
return fs.list(this.root, {
|
||||
ignoreFiles: ['.ignore', '.gitignore', '.bookignore'],
|
||||
@@ -637,18 +651,18 @@ Book.prototype.listAllFiles = function() {
|
||||
|
||||
// Return true if the book is a multilingual book
|
||||
Book.prototype.isMultilingual = function(filename) {
|
||||
return this.books.length > 0;
|
||||
return this.books.length > 0;
|
||||
};
|
||||
|
||||
// Return root of the parent
|
||||
Book.prototype.parentRoot = function() {
|
||||
if (this.parent) return this.parent.parentRoot();
|
||||
return this.root;
|
||||
if (this.parent) return this.parent.parentRoot();
|
||||
return this.root;
|
||||
};
|
||||
|
||||
// Return true if it's a sub-book
|
||||
Book.prototype.isSubBook = function() {
|
||||
return !!this.parent;
|
||||
return !!this.parent;
|
||||
};
|
||||
|
||||
// Test if the file is the entry point
|
||||
@@ -676,11 +690,11 @@ Book.prototype.contentLink = function(link) {
|
||||
|
||||
// Index a page into the search index
|
||||
Book.prototype.indexPage = function(page) {
|
||||
var nav = this.navigation[page.path];
|
||||
if (!nav) return;
|
||||
var nav = this.navigation[page.path];
|
||||
if (!nav) return;
|
||||
|
||||
this.log.debug.ln("index page", page.path);
|
||||
this.searchIndex.add({
|
||||
this.log.debug.ln("index page", page.path);
|
||||
this.searchIndex.add({
|
||||
url: this.contentLink(page.path),
|
||||
title: nav.title,
|
||||
body: pageUtil.extractText(page.sections),
|
||||
@@ -700,12 +714,12 @@ Book.prototype._defaultsStructure = function(filename) {
|
||||
|
||||
// Change output path
|
||||
Book.prototype.setOutput = function(p) {
|
||||
var that = this;
|
||||
this.options.output = path.resolve(p);
|
||||
var that = this;
|
||||
this.options.output = path.resolve(p);
|
||||
|
||||
_.each(this.books, function(book) {
|
||||
book.setOutput(path.join(that.options.output, book.options.language));
|
||||
});
|
||||
_.each(this.books, function(book) {
|
||||
book.setOutput(path.join(that.options.output, book.options.language));
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
+20
-12
@@ -64,10 +64,10 @@ function normalizePluginsNames(plugins) {
|
||||
var Configuration = function(book, options) {
|
||||
var that = this;
|
||||
|
||||
this.book = book;
|
||||
this.book = book;
|
||||
|
||||
this.options = _.cloneDeep(Configuration.DEFAULT);
|
||||
this.options = _.merge(this.options, options || {});
|
||||
this.options = _.merge(this.options, options || {});
|
||||
|
||||
// options.input == book.root
|
||||
Object.defineProperty(this.options, "input", {
|
||||
@@ -79,15 +79,15 @@ var Configuration = function(book, options) {
|
||||
|
||||
// Read and parse the configuration
|
||||
Configuration.prototype.load = function() {
|
||||
var that = this;
|
||||
var that = this;
|
||||
|
||||
return Q()
|
||||
return Q()
|
||||
.then(function() {
|
||||
try {
|
||||
var _config = require(path.resolve(that.book.root, that.options.configFile));
|
||||
that.options = _.merge(
|
||||
that.options,
|
||||
_.omit(_config, 'configFile', 'defaultsPlugins', 'generator', 'extension')
|
||||
that.options,
|
||||
_.omit(_config, 'configFile', 'defaultsPlugins', 'generator', 'extension')
|
||||
);
|
||||
}
|
||||
catch(err) {
|
||||
@@ -96,17 +96,23 @@ Configuration.prototype.load = function() {
|
||||
}
|
||||
})
|
||||
.then(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"));
|
||||
}
|
||||
|
||||
that.options.output = path.resolve(that.options.output || path.join(that.book.root, "_book"));
|
||||
that.options.plugins = normalizePluginsList(that.options.plugins);
|
||||
that.options.defaultsPlugins = normalizePluginsList(that.options.defaultsPlugins || "");
|
||||
that.options.plugins = _.union(that.options.plugins, that.options.defaultsPlugins);
|
||||
that.options.plugins = _.uniq(that.options.plugins, "name");
|
||||
|
||||
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"));
|
||||
// Default value for text direction (from language)
|
||||
if (!that.options.direction) {
|
||||
var lang = i18n.getByLanguage(that.options.language);
|
||||
if (lang) that.options.direction = lang.direction;
|
||||
}
|
||||
|
||||
that.options.gitbook = pkg.version;
|
||||
@@ -133,7 +139,7 @@ Configuration.prototype.normalizeLanguage = function() {
|
||||
Configuration.DEFAULT = {
|
||||
// Options that can't be extend
|
||||
"configFile": "book",
|
||||
"generator": "site",
|
||||
"generator": "website",
|
||||
"extension": null,
|
||||
|
||||
// Book metadats (somes are extracted from the README by default)
|
||||
@@ -141,6 +147,8 @@ Configuration.DEFAULT = {
|
||||
"description": null,
|
||||
"isbn": null,
|
||||
"language": "en",
|
||||
"direction": null,
|
||||
"author": null,
|
||||
|
||||
// version of gitbook to use
|
||||
"gitbook": "*",
|
||||
|
||||
@@ -30,7 +30,7 @@ Generator.prototype.prepareTemplates = function() {
|
||||
this.templates["summary"] = this.book.plugins.template("ebook:summary") || path.resolve(this.options.theme, 'templates/ebook/summary.html');
|
||||
this.templates["glossary"] = this.book.plugins.template("ebook:glossary") || path.resolve(this.options.theme, 'templates/ebook/glossary.html');
|
||||
|
||||
return Q();
|
||||
return Q();
|
||||
};
|
||||
|
||||
// Generate table of contents
|
||||
@@ -64,6 +64,8 @@ Generator.prototype.finish = function() {
|
||||
"--comments": that.options.description,
|
||||
"--isbn": that.options.isbn,
|
||||
"--authors": that.options.author,
|
||||
"--language": that.options.language,
|
||||
"--book-producer": "GitBook",
|
||||
"--publisher": "GitBook",
|
||||
"--chapter": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter ')]",
|
||||
"--chapter-mark": "pagebreak",
|
||||
@@ -91,6 +93,10 @@ Generator.prototype.finish = function() {
|
||||
"--pdf-header-template": String(pdfOptions.headerTemplate) || "<p class='header'><span>"+that.options.title+"</span></p>",
|
||||
"--pdf-footer-template": String(pdfOptions.footerTemplate) || "<p class='footer'><span>_SECTION_</span> <span style='float:right;'>_PAGENUM_</span></p>"
|
||||
});
|
||||
} else if (that.ebookFormat == "epub") {
|
||||
_.extend(_options, {
|
||||
"--dont-split-on-page-breaks": true
|
||||
});
|
||||
}
|
||||
|
||||
var command = [
|
||||
|
||||
@@ -2,10 +2,10 @@ var _ = require("lodash");
|
||||
var EbookGenerator = require("./ebook");
|
||||
|
||||
module.exports = {
|
||||
json: require("./json"),
|
||||
website: require("./website"),
|
||||
ebook: EbookGenerator,
|
||||
pdf: _.partialRight(EbookGenerator, "pdf"),
|
||||
mobi: _.partialRight(EbookGenerator, "mobi"),
|
||||
epub: _.partialRight(EbookGenerator, "epub")
|
||||
json: require("./json"),
|
||||
website: require("./website"),
|
||||
ebook: EbookGenerator,
|
||||
pdf: _.partialRight(EbookGenerator, "pdf"),
|
||||
mobi: _.partialRight(EbookGenerator, "mobi"),
|
||||
epub: _.partialRight(EbookGenerator, "epub")
|
||||
};
|
||||
|
||||
+18
-18
@@ -64,11 +64,11 @@ Generator.prototype.prepareStyles = function() {
|
||||
|
||||
// Prepare templates
|
||||
Generator.prototype.prepareTemplates = function() {
|
||||
this.templates["page"] = this.book.plugins.template("site:page") || path.resolve(this.options.theme, 'templates/website/page.html');
|
||||
this.templates["page"] = this.book.plugins.template("site:page") || path.resolve(this.options.theme, 'templates/website/page.html');
|
||||
this.templates["langs"] = this.book.plugins.template("site:langs") || path.resolve(this.options.theme, 'templates/website/langs.html');
|
||||
this.templates["glossary"] = this.book.plugins.template("site:glossary") || path.resolve(this.options.theme, 'templates/website/glossary.html');
|
||||
|
||||
return Q();
|
||||
return Q();
|
||||
};
|
||||
|
||||
// Prepare template engine
|
||||
@@ -213,38 +213,38 @@ Generator.prototype._writeTemplate = function(tpl, options, output, interpolate)
|
||||
interpolate = interpolate || _.identity;
|
||||
return Q()
|
||||
.then(function(sections) {
|
||||
return that.env.render(
|
||||
tpl,
|
||||
_.extend({
|
||||
return that.env.render(
|
||||
tpl,
|
||||
_.extend({
|
||||
gitbook: {
|
||||
version: pkg.version
|
||||
},
|
||||
|
||||
styles: that.styles,
|
||||
styles: that.styles,
|
||||
|
||||
revision: that.revision,
|
||||
revision: that.revision,
|
||||
|
||||
title: that.options.title,
|
||||
description: that.options.description,
|
||||
title: that.options.title,
|
||||
description: that.options.description,
|
||||
language: that.book.config.normalizeLanguage(),
|
||||
|
||||
glossary: that.book.glossary,
|
||||
glossary: that.book.glossary,
|
||||
|
||||
summary: that.book.summary,
|
||||
allNavigation: that.book.navigation,
|
||||
summary: that.book.summary,
|
||||
allNavigation: that.book.navigation,
|
||||
|
||||
plugins: {
|
||||
plugins: {
|
||||
resources: that.book.plugins.resources(that.namespace)
|
||||
},
|
||||
pluginsConfig: JSON.stringify(that.options.pluginsConfig),
|
||||
htmlSnippet: _.partial(_.partialRight(that.book.plugins.html, that, options), that.namespace),
|
||||
pluginsConfig: JSON.stringify(that.options.pluginsConfig),
|
||||
htmlSnippet: _.partial(_.partialRight(that.book.plugins.html, that, options), that.namespace),
|
||||
|
||||
options: that.options,
|
||||
options: that.options,
|
||||
|
||||
basePath: ".",
|
||||
staticBase: path.join(".", "gitbook"),
|
||||
}, options)
|
||||
);
|
||||
}, options)
|
||||
);
|
||||
})
|
||||
.then(interpolate)
|
||||
.then(function(html) {
|
||||
|
||||
+170
-170
@@ -12,199 +12,199 @@ var watch = require("./utils/watch");
|
||||
var logger = require("./utils/logger");
|
||||
|
||||
var LOG_OPTION = {
|
||||
name: "log",
|
||||
description: "Minimum log level to display",
|
||||
values: _.chain(logger.LEVELS).keys().map(stringUtils.toLowerCase).value(),
|
||||
defaults: "info"
|
||||
name: "log",
|
||||
description: "Minimum log level to display",
|
||||
values: _.chain(logger.LEVELS).keys().map(stringUtils.toLowerCase).value(),
|
||||
defaults: "info"
|
||||
};
|
||||
|
||||
var FORMAT_OPTION = {
|
||||
name: "format",
|
||||
description: "Format to build to",
|
||||
values: ["website", "json", "ebook"],
|
||||
defaults: "website"
|
||||
name: "format",
|
||||
description: "Format to build to",
|
||||
values: ["website", "json", "ebook"],
|
||||
defaults: "website"
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
Book: Book,
|
||||
LOG_LEVELS: logger.LEVELS,
|
||||
Book: Book,
|
||||
LOG_LEVELS: logger.LEVELS,
|
||||
|
||||
commands: _.flatten([
|
||||
{
|
||||
name: "build [book] [output]",
|
||||
description: "build a book",
|
||||
options: [
|
||||
FORMAT_OPTION,
|
||||
LOG_OPTION
|
||||
],
|
||||
exec: function(args, kwargs) {
|
||||
var input = args[0] || process.cwd();
|
||||
var output = args[1] || path.join(input, "_book");
|
||||
commands: _.flatten([
|
||||
{
|
||||
name: "build [book] [output]",
|
||||
description: "build a book",
|
||||
options: [
|
||||
FORMAT_OPTION,
|
||||
LOG_OPTION
|
||||
],
|
||||
exec: function(args, kwargs) {
|
||||
var input = args[0] || process.cwd();
|
||||
var output = args[1] || path.join(input, "_book");
|
||||
|
||||
var book = new Book(input, _.extend({}, {
|
||||
'config': {
|
||||
'output': output
|
||||
},
|
||||
'logLevel': kwargs.log
|
||||
}));
|
||||
var book = new Book(input, _.extend({}, {
|
||||
'config': {
|
||||
'output': output
|
||||
},
|
||||
'logLevel': kwargs.log
|
||||
}));
|
||||
|
||||
return book.parse()
|
||||
.then(function() {
|
||||
return book.generate(kwargs.format);
|
||||
})
|
||||
.then(function(){
|
||||
console.log("");
|
||||
console.log(color.green("Done, without error"));
|
||||
});
|
||||
}
|
||||
},
|
||||
return book.parse()
|
||||
.then(function() {
|
||||
return book.generate(kwargs.format);
|
||||
})
|
||||
.then(function(){
|
||||
console.log("");
|
||||
console.log(color.green("Done, without error"));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_.map(["pdf", "epub", "mobi"], function(ebookType) {
|
||||
return {
|
||||
name: ebookType+" [book] [output]",
|
||||
description: "build a book to "+ebookType,
|
||||
options: [
|
||||
LOG_OPTION
|
||||
],
|
||||
exec: function(args, kwargs) {
|
||||
var input = args[0] || process.cwd();
|
||||
var output = args[1];
|
||||
_.map(["pdf", "epub", "mobi"], function(ebookType) {
|
||||
return {
|
||||
name: ebookType+" [book] [output]",
|
||||
description: "build a book to "+ebookType,
|
||||
options: [
|
||||
LOG_OPTION
|
||||
],
|
||||
exec: function(args, kwargs) {
|
||||
var input = args[0] || process.cwd();
|
||||
var output = args[1];
|
||||
|
||||
var book = new Book(input, _.extend({}, {
|
||||
'logLevel': kwargs.log
|
||||
}));
|
||||
var book = new Book(input, _.extend({}, {
|
||||
'logLevel': kwargs.log
|
||||
}));
|
||||
|
||||
return book.parse()
|
||||
.then(function() {
|
||||
return book.generateFile(output, {
|
||||
ebookFormat: ebookType
|
||||
});
|
||||
})
|
||||
.then(function(){
|
||||
console.log("");
|
||||
console.log(color.green("Done, without error"));
|
||||
});
|
||||
}
|
||||
};
|
||||
}),
|
||||
return book.parse()
|
||||
.then(function() {
|
||||
return book.generateFile(output, {
|
||||
ebookFormat: ebookType
|
||||
});
|
||||
})
|
||||
.then(function(){
|
||||
console.log("");
|
||||
console.log(color.green("Done, without error"));
|
||||
});
|
||||
}
|
||||
};
|
||||
}),
|
||||
|
||||
{
|
||||
name: "serve [book]",
|
||||
description: "Build then serve a gitbook from a directory",
|
||||
options: [
|
||||
{
|
||||
name: "port",
|
||||
description: "Port for server to listen on",
|
||||
defaults: 4000
|
||||
},
|
||||
{
|
||||
name: "lrport",
|
||||
description: "Port for livereload server to listen on",
|
||||
defaults: 35729
|
||||
},
|
||||
{
|
||||
name: "watch",
|
||||
description: "Enable/disable file watcher",
|
||||
defaults: true
|
||||
},
|
||||
FORMAT_OPTION,
|
||||
LOG_OPTION
|
||||
],
|
||||
exec: function(args, kwargs) {
|
||||
var input = args[0] || process.cwd();
|
||||
var server = new Server();
|
||||
{
|
||||
name: "serve [book]",
|
||||
description: "Build then serve a gitbook from a directory",
|
||||
options: [
|
||||
{
|
||||
name: "port",
|
||||
description: "Port for server to listen on",
|
||||
defaults: 4000
|
||||
},
|
||||
{
|
||||
name: "lrport",
|
||||
description: "Port for livereload server to listen on",
|
||||
defaults: 35729
|
||||
},
|
||||
{
|
||||
name: "watch",
|
||||
description: "Enable/disable file watcher",
|
||||
defaults: true
|
||||
},
|
||||
FORMAT_OPTION,
|
||||
LOG_OPTION
|
||||
],
|
||||
exec: function(args, kwargs) {
|
||||
var input = args[0] || process.cwd();
|
||||
var server = new Server();
|
||||
|
||||
// Init livereload server
|
||||
var lrServer = tinylr({});
|
||||
var lrPath = undefined;
|
||||
// Init livereload server
|
||||
var lrServer = tinylr({});
|
||||
var lrPath = undefined;
|
||||
|
||||
var generate = function() {
|
||||
if (server.isRunning()) console.log("Stopping server");
|
||||
var generate = function() {
|
||||
if (server.isRunning()) console.log("Stopping server");
|
||||
|
||||
return server.stop()
|
||||
.then(function() {
|
||||
var book = new Book(input, _.extend({}, {
|
||||
'config': {
|
||||
'defaultsPlugins': ["livereload"]
|
||||
},
|
||||
'logLevel': kwargs.log
|
||||
}));
|
||||
return server.stop()
|
||||
.then(function() {
|
||||
var book = new Book(input, _.extend({}, {
|
||||
'config': {
|
||||
'defaultsPlugins': ["livereload"]
|
||||
},
|
||||
'logLevel': kwargs.log
|
||||
}));
|
||||
|
||||
return book.parse()
|
||||
.then(function() {
|
||||
return book.generate(kwargs.format);
|
||||
})
|
||||
.thenResolve(book);
|
||||
})
|
||||
.then(function(book) {
|
||||
console.log();
|
||||
console.log('Starting server ...');
|
||||
return server.start(book.options.output, kwargs.port)
|
||||
.then(function() {
|
||||
console.log('Serving book on http://localhost:'+kwargs.port);
|
||||
return book.parse()
|
||||
.then(function() {
|
||||
return book.generate(kwargs.format);
|
||||
})
|
||||
.thenResolve(book);
|
||||
})
|
||||
.then(function(book) {
|
||||
console.log();
|
||||
console.log('Starting server ...');
|
||||
return server.start(book.options.output, kwargs.port)
|
||||
.then(function() {
|
||||
console.log('Serving book on http://localhost:'+kwargs.port);
|
||||
|
||||
if (lrPath) {
|
||||
// trigger livereload
|
||||
lrServer.changed({
|
||||
body: {
|
||||
files: [lrPath]
|
||||
}
|
||||
});
|
||||
}
|
||||
if (lrPath) {
|
||||
// trigger livereload
|
||||
lrServer.changed({
|
||||
body: {
|
||||
files: [lrPath]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!kwargs.watch) return;
|
||||
if (!kwargs.watch) return;
|
||||
|
||||
return watch(book.root)
|
||||
.then(function(filepath) {
|
||||
// set livereload path
|
||||
lrPath = filepath;
|
||||
console.log("Restart after change in files");
|
||||
console.log('');
|
||||
return generate();
|
||||
})
|
||||
})
|
||||
});
|
||||
};
|
||||
return watch(book.root)
|
||||
.then(function(filepath) {
|
||||
// set livereload path
|
||||
lrPath = filepath;
|
||||
console.log("Restart after change in files");
|
||||
console.log('');
|
||||
return generate();
|
||||
})
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
return Q.nfcall(lrServer.listen.bind(lrServer), kwargs.lrport)
|
||||
.then(function() {
|
||||
console.log('Live reload server started on port:', kwargs.lrport);
|
||||
console.log('Press CTRL+C to quit ...');
|
||||
console.log('')
|
||||
return generate();
|
||||
});
|
||||
}
|
||||
},
|
||||
return Q.nfcall(lrServer.listen.bind(lrServer), kwargs.lrport)
|
||||
.then(function() {
|
||||
console.log('Live reload server started on port:', kwargs.lrport);
|
||||
console.log('Press CTRL+C to quit ...');
|
||||
console.log('')
|
||||
return generate();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "install [book]",
|
||||
description: "install plugins dependencies",
|
||||
exec: function(args, kwargs) {
|
||||
var input = args[0] || process.cwd();
|
||||
{
|
||||
name: "install [book]",
|
||||
description: "install plugins dependencies",
|
||||
exec: function(args, kwargs) {
|
||||
var input = args[0] || process.cwd();
|
||||
|
||||
var book = new Book(input);
|
||||
var book = new Book(input);
|
||||
|
||||
return book.config.load()
|
||||
.then(function() {
|
||||
return book.plugins.install();
|
||||
})
|
||||
.then(function(){
|
||||
console.log("");
|
||||
console.log(color.green("Done, without error"));
|
||||
});
|
||||
}
|
||||
},
|
||||
return book.config.load()
|
||||
.then(function() {
|
||||
return book.plugins.install();
|
||||
})
|
||||
.then(function(){
|
||||
console.log("");
|
||||
console.log(color.green("Done, without error"));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "init [directory]",
|
||||
description: "create files and folders based on contents of SUMMARY.md",
|
||||
exec: function(args, kwargs) {
|
||||
return Book.init(args[0] || process.cwd())
|
||||
.then(function(){
|
||||
console.log("");
|
||||
console.log(color.green("Done, without error"));
|
||||
});
|
||||
}
|
||||
}
|
||||
])
|
||||
{
|
||||
name: "init [directory]",
|
||||
description: "create files and folders based on contents of SUMMARY.md",
|
||||
exec: function(args, kwargs) {
|
||||
return Book.init(args[0] || process.cwd())
|
||||
.then(function(){
|
||||
console.log("");
|
||||
console.log(color.green("Done, without error"));
|
||||
});
|
||||
}
|
||||
}
|
||||
])
|
||||
};
|
||||
|
||||
+114
-114
@@ -8,113 +8,113 @@ var Plugin = require("./plugin");
|
||||
var pkg = require("../package.json");
|
||||
|
||||
var initNPM = _.memoize(function() {
|
||||
return Q.nfcall(npm.load, { silent: true, loglevel: 'silent' });
|
||||
return Q.nfcall(npm.load, { silent: true, loglevel: 'silent' });
|
||||
});
|
||||
|
||||
|
||||
var PluginsList = function(book, plugins) {
|
||||
this.book = book;
|
||||
this.log = this.book.log;
|
||||
this.book = book;
|
||||
this.log = this.book.log;
|
||||
|
||||
// List of Plugin objects
|
||||
this.list = [];
|
||||
// List of Plugin objects
|
||||
this.list = [];
|
||||
|
||||
// List of names of failed plugins
|
||||
this.failed = [];
|
||||
// List of names of failed plugins
|
||||
this.failed = [];
|
||||
|
||||
// Namespaces
|
||||
this.namespaces = _.chain(["website", "ebook"])
|
||||
.map(function(namespace) {
|
||||
return [
|
||||
namespace,
|
||||
{
|
||||
html: {},
|
||||
resources: _.chain(Plugin.RESOURCES)
|
||||
.map(function(type) {
|
||||
return [type, []];
|
||||
})
|
||||
.object()
|
||||
.value()
|
||||
}
|
||||
];
|
||||
})
|
||||
.object()
|
||||
.value();
|
||||
// Namespaces
|
||||
this.namespaces = _.chain(["website", "ebook"])
|
||||
.map(function(namespace) {
|
||||
return [
|
||||
namespace,
|
||||
{
|
||||
html: {},
|
||||
resources: _.chain(Plugin.RESOURCES)
|
||||
.map(function(type) {
|
||||
return [type, []];
|
||||
})
|
||||
.object()
|
||||
.value()
|
||||
}
|
||||
];
|
||||
})
|
||||
.object()
|
||||
.value();
|
||||
|
||||
// Bind methods
|
||||
_.bindAll(this);
|
||||
// Bind methods
|
||||
_.bindAll(this);
|
||||
|
||||
if (plugins) this.load(plugins);
|
||||
if (plugins) this.load(plugins);
|
||||
};
|
||||
|
||||
// return count of plugins
|
||||
PluginsList.prototype.count = function() {
|
||||
return this.list.length;
|
||||
return this.list.length;
|
||||
};
|
||||
|
||||
// Add and load a plugin
|
||||
PluginsList.prototype.load = function(plugin, options) {
|
||||
var that = this;
|
||||
var that = this;
|
||||
|
||||
if (_.isArray(plugin)) {
|
||||
return _.reduce(plugin, function(prev, p) {
|
||||
return prev.then(function() {
|
||||
return that.load(p);
|
||||
});
|
||||
}, Q());
|
||||
}
|
||||
if (_.isObject(plugin) && !(plugin instanceof Plugin)) plugin = plugin.name;
|
||||
if (_.isString(plugin)) plugin = new Plugin(this.book, plugin);
|
||||
if (_.isArray(plugin)) {
|
||||
return _.reduce(plugin, function(prev, p) {
|
||||
return prev.then(function() {
|
||||
return that.load(p);
|
||||
});
|
||||
}, Q());
|
||||
}
|
||||
if (_.isObject(plugin) && !(plugin instanceof Plugin)) plugin = plugin.name;
|
||||
if (_.isString(plugin)) plugin = new Plugin(this.book, plugin);
|
||||
|
||||
that.log.info("load plugin", plugin.name, "....");
|
||||
if (!plugin.isValid()) {
|
||||
that.log.info.fail();
|
||||
that.failed.push(plugin.name);
|
||||
return Q();
|
||||
that.log.info("load plugin", plugin.name, "....");
|
||||
if (!plugin.isValid()) {
|
||||
that.log.info.fail();
|
||||
that.failed.push(plugin.name);
|
||||
return Q();
|
||||
} else {
|
||||
that.log.info.ok();
|
||||
that.log.info.ok();
|
||||
|
||||
// Push in the list
|
||||
that.list.push(plugin);
|
||||
// Push in the list
|
||||
that.list.push(plugin);
|
||||
}
|
||||
|
||||
// Extract filters
|
||||
_.each(plugin.getFilters(), function(filterFunc, filterName) {
|
||||
// Extract filters
|
||||
_.each(plugin.getFilters(), function(filterFunc, filterName) {
|
||||
that.book.template.addFilter(filterName, filterFunc);
|
||||
});
|
||||
|
||||
// Extract blocks
|
||||
_.each(plugin.getBlocks(), function(block, blockName) {
|
||||
_.each(plugin.getBlocks(), function(block, blockName) {
|
||||
that.book.template.addBlock(blockName, block);
|
||||
});
|
||||
|
||||
return _.reduce(_.keys(that.namespaces), function(prev, namespaceName) {
|
||||
return prev.then(function() {
|
||||
return plugin.getResources(namespaceName)
|
||||
.then(function(plResources) {
|
||||
var namespace = that.namespaces[namespaceName];
|
||||
return _.reduce(_.keys(that.namespaces), function(prev, namespaceName) {
|
||||
return prev.then(function() {
|
||||
return plugin.getResources(namespaceName)
|
||||
.then(function(plResources) {
|
||||
var namespace = that.namespaces[namespaceName];
|
||||
|
||||
// Extract js and css
|
||||
_.each(Plugin.RESOURCES, function(resourceType) {
|
||||
namespace.resources[resourceType] = (namespace.resources[resourceType] || []).concat(plResources[resourceType] || []);
|
||||
});
|
||||
// Extract js and css
|
||||
_.each(Plugin.RESOURCES, function(resourceType) {
|
||||
namespace.resources[resourceType] = (namespace.resources[resourceType] || []).concat(plResources[resourceType] || []);
|
||||
});
|
||||
|
||||
// Map of html resources by name added by each plugin
|
||||
_.each(plResources.html || {}, function(value, tag) {
|
||||
// Turn into function if not one already
|
||||
if (!_.isFunction(value)) value = _.constant(value);
|
||||
// Map of html resources by name added by each plugin
|
||||
_.each(plResources.html || {}, function(value, tag) {
|
||||
// Turn into function if not one already
|
||||
if (!_.isFunction(value)) value = _.constant(value);
|
||||
|
||||
namespace.html[tag] = namespace.html[tag] || [];
|
||||
namespace.html[tag].push(value);
|
||||
});
|
||||
})
|
||||
});
|
||||
}, Q());
|
||||
namespace.html[tag] = namespace.html[tag] || [];
|
||||
namespace.html[tag].push(value);
|
||||
});
|
||||
})
|
||||
});
|
||||
}, Q());
|
||||
};
|
||||
|
||||
// Call a hook
|
||||
PluginsList.prototype.hook = function(name, data) {
|
||||
return _.reduce(this.list, function(prev, plugin) {
|
||||
return _.reduce(this.list, function(prev, plugin) {
|
||||
return prev.then(function(ret) {
|
||||
return plugin.callHook(name, ret);
|
||||
});
|
||||
@@ -123,7 +123,7 @@ PluginsList.prototype.hook = function(name, data) {
|
||||
|
||||
// Return a template from a plugin
|
||||
PluginsList.prototype.template = function(name) {
|
||||
var withTpl = _.find(this.list, function(plugin) {
|
||||
var withTpl = _.find(this.list, function(plugin) {
|
||||
return (
|
||||
plugin.infos.templates &&
|
||||
plugin.infos.templates[name]
|
||||
@@ -136,7 +136,7 @@ PluginsList.prototype.template = function(name) {
|
||||
|
||||
// Return an html snippet
|
||||
PluginsList.prototype.html = function(namespace, tag, context, options) {
|
||||
var htmlSnippets = this.namespaces[namespace].html[tag];
|
||||
var htmlSnippets = this.namespaces[namespace].html[tag];
|
||||
return _.map(htmlSnippets || [], function(code) {
|
||||
return code.call(context, options);
|
||||
}).join("\n");
|
||||
@@ -144,13 +144,13 @@ PluginsList.prototype.html = function(namespace, tag, context, options) {
|
||||
|
||||
// Return a resources map for a namespace
|
||||
PluginsList.prototype.resources = function(namespace) {
|
||||
return this.namespaces[namespace].resources;
|
||||
return this.namespaces[namespace].resources;
|
||||
};
|
||||
|
||||
// Install plugins from a book
|
||||
PluginsList.prototype.install = function() {
|
||||
var that = this;
|
||||
var defaultsPlugins = _.pluck(that.book.options.defaultsPlugins)
|
||||
var that = this;
|
||||
var defaultsPlugins = _.pluck(that.book.options.defaultsPlugins)
|
||||
|
||||
// Remove defaults (no need to install)
|
||||
var plugins = _.filter(that.book.options.plugins, function(plugin) {
|
||||
@@ -167,51 +167,51 @@ PluginsList.prototype.install = function() {
|
||||
|
||||
// Resolve version if needed
|
||||
.then(function() {
|
||||
if (plugin.version) return plugin.version;
|
||||
if (plugin.version) return plugin.version;
|
||||
|
||||
that.book.log.info.ln("No version specified, resolve plugin", plugin.name);
|
||||
return initNPM()
|
||||
.then(function() {
|
||||
return Q.nfcall(npm.commands.view, [fullname+"@*", "engines"], true);
|
||||
})
|
||||
.then(function(versions) {
|
||||
return _.chain(versions)
|
||||
.pairs()
|
||||
.map(function(v) {
|
||||
return {
|
||||
version: v[0],
|
||||
gitbook: (v[1].engines || {})["gitbook"]
|
||||
}
|
||||
})
|
||||
.filter(function(v) {
|
||||
return v.gitbook && semver.satisfies(pkg.version, v.gitbook);
|
||||
})
|
||||
.sort(function(v1, v2) {
|
||||
return semver.lt(v1.version, v2.version)? 1 : -1;
|
||||
})
|
||||
.pluck("version")
|
||||
.first()
|
||||
.value();
|
||||
});
|
||||
that.book.log.info.ln("No version specified, resolve plugin", plugin.name);
|
||||
return initNPM()
|
||||
.then(function() {
|
||||
return Q.nfcall(npm.commands.view, [fullname+"@*", "engines"], true);
|
||||
})
|
||||
.then(function(versions) {
|
||||
return _.chain(versions)
|
||||
.pairs()
|
||||
.map(function(v) {
|
||||
return {
|
||||
version: v[0],
|
||||
gitbook: (v[1].engines || {})["gitbook"]
|
||||
}
|
||||
})
|
||||
.filter(function(v) {
|
||||
return v.gitbook && semver.satisfies(pkg.version, v.gitbook);
|
||||
})
|
||||
.sort(function(v1, v2) {
|
||||
return semver.lt(v1.version, v2.version)? 1 : -1;
|
||||
})
|
||||
.pluck("version")
|
||||
.first()
|
||||
.value();
|
||||
});
|
||||
})
|
||||
|
||||
// Install the plugin with the resolved version
|
||||
.then(function(version) {
|
||||
if (!version) {
|
||||
throw "Found no satisfactory version for plugin "+plugin.name;
|
||||
}
|
||||
if (!version) {
|
||||
throw "Found no satisfactory version for plugin "+plugin.name;
|
||||
}
|
||||
|
||||
that.book.log.info.ln("install plugin", plugin.name, "from npm ("+fullname+") with version", version);
|
||||
return Q.nfcall(npmi, {
|
||||
'name': fullname,
|
||||
'version': version,
|
||||
'path': that.book.root,
|
||||
'npmLoad': {
|
||||
'loglevel': 'silent',
|
||||
'loaded': true,
|
||||
'prefix': that.book.root
|
||||
}
|
||||
});
|
||||
that.book.log.info.ln("install plugin", plugin.name, "from npm ("+fullname+") with version", version);
|
||||
return Q.nfcall(npmi, {
|
||||
'name': fullname,
|
||||
'version': version,
|
||||
'path': that.book.root,
|
||||
'npmLoad': {
|
||||
'loglevel': 'silent',
|
||||
'loaded': true,
|
||||
'prefix': that.book.root
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(function() {
|
||||
that.book.log.info.ok("plugin", plugin.name, "installed with success");
|
||||
|
||||
+39
-38
@@ -12,31 +12,31 @@ var pkg = require("../package.json");
|
||||
|
||||
// The loader should handle relative and git url
|
||||
var BookLoader = nunjucks.Loader.extend({
|
||||
async: true,
|
||||
async: true,
|
||||
|
||||
init: function(book) {
|
||||
this.book = book;
|
||||
this.book = book;
|
||||
},
|
||||
|
||||
getSource: function(fileurl, callback) {
|
||||
var that = this;
|
||||
var that = this;
|
||||
|
||||
git.resolveFile(fileurl)
|
||||
.then(function(filepath) {
|
||||
// Is local file
|
||||
if (!filepath) filepath = path.resolve(that.book.root, fileurl);
|
||||
else that.book.log.debug.ln("resolve from git", fileurl, "to", filepath)
|
||||
git.resolveFile(fileurl)
|
||||
.then(function(filepath) {
|
||||
// Is local file
|
||||
if (!filepath) filepath = path.resolve(that.book.root, fileurl);
|
||||
else that.book.log.debug.ln("resolve from git", fileurl, "to", filepath)
|
||||
|
||||
// Read file from absolute path
|
||||
return fs.readFile(filepath)
|
||||
.then(function(source) {
|
||||
return {
|
||||
src: source.toString(),
|
||||
path: filepath
|
||||
}
|
||||
});
|
||||
})
|
||||
.nodeify(callback);
|
||||
// Read file from absolute path
|
||||
return fs.readFile(filepath)
|
||||
.then(function(source) {
|
||||
return {
|
||||
src: source.toString(),
|
||||
path: filepath
|
||||
}
|
||||
});
|
||||
})
|
||||
.nodeify(callback);
|
||||
},
|
||||
|
||||
resolve: function(from, to) {
|
||||
@@ -46,27 +46,27 @@ var BookLoader = nunjucks.Loader.extend({
|
||||
|
||||
|
||||
var TemplateEngine = function(book) {
|
||||
this.book = book;
|
||||
this.book = book;
|
||||
this.log = this.book.log;
|
||||
|
||||
// Nunjucks env
|
||||
this.env = new nunjucks.Environment(
|
||||
new BookLoader(book),
|
||||
{
|
||||
// Escaping is done after by the markdown parser
|
||||
autoescape: false,
|
||||
// Nunjucks env
|
||||
this.env = new nunjucks.Environment(
|
||||
new BookLoader(book),
|
||||
{
|
||||
// Escaping is done after by the markdown parser
|
||||
autoescape: false,
|
||||
|
||||
// Tags
|
||||
tags: {
|
||||
blockStart: '{%',
|
||||
blockEnd: '%}',
|
||||
variableStart: '{{',
|
||||
variableEnd: '}}',
|
||||
commentStart: '{###',
|
||||
commentEnd: '###}'
|
||||
}
|
||||
}
|
||||
);
|
||||
// Tags
|
||||
tags: {
|
||||
blockStart: '{%',
|
||||
blockEnd: '%}',
|
||||
variableStart: '{{',
|
||||
variableEnd: '}}',
|
||||
commentStart: '{###',
|
||||
commentEnd: '###}'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// List of tags shortcuts
|
||||
this.shortcuts = [];
|
||||
@@ -318,7 +318,8 @@ TemplateEngine.prototype.renderString = function(content, context, options) {
|
||||
|
||||
// infos about gitbook
|
||||
gitbook: {
|
||||
version: pkg.version
|
||||
version: pkg.version,
|
||||
generator: this.book.options.generator
|
||||
}
|
||||
});
|
||||
options = _.defaults(options || {}, {
|
||||
@@ -335,7 +336,7 @@ TemplateEngine.prototype.renderString = function(content, context, options) {
|
||||
|
||||
// Render a file from the book
|
||||
TemplateEngine.prototype.renderFile = function(filename, options) {
|
||||
var that = this, context;
|
||||
var that = this, context;
|
||||
|
||||
return that.book.readFile(filename)
|
||||
.then(function(content) {
|
||||
|
||||
@@ -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
|
||||
};
|
||||
+58
-58
@@ -15,7 +15,7 @@ var GIT_TMP = null;
|
||||
|
||||
// Check if an url is a git dependency url
|
||||
function checkGitUrl(giturl) {
|
||||
return (giturl.indexOf(GIT_PREFIX) === 0);
|
||||
return (giturl.indexOf(GIT_PREFIX) === 0);
|
||||
}
|
||||
|
||||
// Validates a SHA in hexadecimal
|
||||
@@ -25,88 +25,88 @@ function validateSha(str) {
|
||||
|
||||
// Parse and extract infos
|
||||
function parseGitUrl(giturl) {
|
||||
var ref, uri, fileParts, filepath;
|
||||
var ref, uri, fileParts, filepath;
|
||||
|
||||
if (!checkGitUrl(giturl)) return null;
|
||||
giturl = giturl.slice(GIT_PREFIX.length);
|
||||
if (!checkGitUrl(giturl)) return null;
|
||||
giturl = giturl.slice(GIT_PREFIX.length);
|
||||
|
||||
uri = new URI(giturl);
|
||||
ref = uri.fragment() || "master";
|
||||
uri.fragment(null);
|
||||
uri = new URI(giturl);
|
||||
ref = uri.fragment() || "master";
|
||||
uri.fragment(null);
|
||||
|
||||
// Extract file inside the repo (after the .git)
|
||||
fileParts =uri.path().split(".git");
|
||||
filepath = fileParts.length > 1? fileParts.slice(1).join(".git") : "";
|
||||
if (filepath[0] == "/") filepath = filepath.slice(1);
|
||||
// Extract file inside the repo (after the .git)
|
||||
fileParts =uri.path().split(".git");
|
||||
filepath = fileParts.length > 1? fileParts.slice(1).join(".git") : "";
|
||||
if (filepath[0] == "/") filepath = filepath.slice(1);
|
||||
|
||||
// Recreate pathname without the real filename
|
||||
uri.path(_.first(fileParts)+".git");
|
||||
// Recreate pathname without the real filename
|
||||
uri.path(_.first(fileParts)+".git");
|
||||
|
||||
return {
|
||||
host: uri.toString(),
|
||||
ref: ref || "master",
|
||||
filepath: filepath
|
||||
};
|
||||
return {
|
||||
host: uri.toString(),
|
||||
ref: ref || "master",
|
||||
filepath: filepath
|
||||
};
|
||||
}
|
||||
|
||||
// Clone a git repo from a specific ref
|
||||
function cloneGitRepo(host, ref) {
|
||||
var isBranch = false;
|
||||
var isBranch = false;
|
||||
|
||||
ref = ref || "master";
|
||||
if (!validateSha(ref)) isBranch = true;
|
||||
ref = ref || "master";
|
||||
if (!validateSha(ref)) isBranch = true;
|
||||
|
||||
return Q()
|
||||
return Q()
|
||||
|
||||
// Create temporary folder to store git repos
|
||||
.then(function() {
|
||||
if (GIT_TMP) return;
|
||||
return fs.tmp.dir()
|
||||
.then(function(_tmp) {
|
||||
GIT_TMP = _tmp;
|
||||
});
|
||||
})
|
||||
// Create temporary folder to store git repos
|
||||
.then(function() {
|
||||
if (GIT_TMP) return;
|
||||
return fs.tmp.dir()
|
||||
.then(function(_tmp) {
|
||||
GIT_TMP = _tmp;
|
||||
});
|
||||
})
|
||||
|
||||
// Return or clone the git repo
|
||||
.then(function() {
|
||||
// Unique ID for repo/ref combinaison
|
||||
var repoId = crc.crc32(host+"#"+ref).toString(16);
|
||||
// Return or clone the git repo
|
||||
.then(function() {
|
||||
// Unique ID for repo/ref combinaison
|
||||
var repoId = crc.crc32(host+"#"+ref).toString(16);
|
||||
|
||||
// Absolute path to the folder
|
||||
var repoPath = path.resolve(GIT_TMP, repoId);
|
||||
// Absolute path to the folder
|
||||
var repoPath = path.resolve(GIT_TMP, repoId);
|
||||
|
||||
return fs.exists(repoPath)
|
||||
.then(function(doExists) {
|
||||
if (doExists) return;
|
||||
return fs.exists(repoPath)
|
||||
.then(function(doExists) {
|
||||
if (doExists) return;
|
||||
|
||||
// Clone repo
|
||||
return exec("git clone "+host+" "+repoPath)
|
||||
.then(function() {
|
||||
return exec("git checkout "+ref, { cwd: repoPath });
|
||||
})
|
||||
})
|
||||
.thenResolve(repoPath);
|
||||
});
|
||||
// Clone repo
|
||||
return exec("git clone "+host+" "+repoPath)
|
||||
.then(function() {
|
||||
return exec("git checkout "+ref, { cwd: repoPath });
|
||||
})
|
||||
})
|
||||
.thenResolve(repoPath);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Get file from a git repo
|
||||
function resolveFileFromGit(giturl) {
|
||||
if (_.isString(giturl)) giturl = parseGitUrl(giturl);
|
||||
if (!giturl) return Q(null);
|
||||
if (_.isString(giturl)) giturl = parseGitUrl(giturl);
|
||||
if (!giturl) return Q(null);
|
||||
|
||||
// Clone or get from cache
|
||||
return cloneGitRepo(giturl.host, giturl.ref)
|
||||
.then(function(repo) {
|
||||
// Clone or get from cache
|
||||
return cloneGitRepo(giturl.host, giturl.ref)
|
||||
.then(function(repo) {
|
||||
|
||||
// Resolve relative path
|
||||
return path.resolve(repo, giturl.filepath);
|
||||
});
|
||||
// Resolve relative path
|
||||
return path.resolve(repo, giturl.filepath);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
module.exports = {
|
||||
checkUrl: checkGitUrl,
|
||||
parseUrl: parseGitUrl,
|
||||
resolveFile: resolveFileFromGit
|
||||
checkUrl: checkGitUrl,
|
||||
parseUrl: parseGitUrl,
|
||||
resolveFile: resolveFileFromGit
|
||||
};
|
||||
|
||||
+40
-38
@@ -5,12 +5,14 @@ var fs = require("fs");
|
||||
var I18N_PATH = path.resolve(__dirname, "../../theme/i18n/")
|
||||
|
||||
var getLocales = _.memoize(function() {
|
||||
var locales = fs.readdirSync(I18N_PATH);
|
||||
return _.chain(locales)
|
||||
var locales = fs.readdirSync(I18N_PATH);
|
||||
return _.chain(locales)
|
||||
.map(function(local) {
|
||||
local = path.basename(local, ".json");
|
||||
return [local, _.extend(require(path.join(I18N_PATH, local)), {
|
||||
id: local
|
||||
return [local, _.extend({
|
||||
direction: "ltr"
|
||||
}, require(path.join(I18N_PATH, local)), {
|
||||
id: local
|
||||
})];
|
||||
})
|
||||
.object()
|
||||
@@ -18,53 +20,53 @@ var getLocales = _.memoize(function() {
|
||||
});
|
||||
|
||||
var getLanguages = function() {
|
||||
return _.keys(getLocales());
|
||||
return _.keys(getLocales());
|
||||
};
|
||||
|
||||
var getByLanguage = function(lang) {
|
||||
lang = normalizeLanguage(lang);
|
||||
var locales = getLocales();
|
||||
return locales[lang];
|
||||
lang = normalizeLanguage(lang);
|
||||
var locales = getLocales();
|
||||
return locales[lang];
|
||||
};
|
||||
|
||||
var compareLocales = function(lang, locale) {
|
||||
var langMain = _.first(lang.split("-"));
|
||||
var langSecond = _.last(lang.split("-"));
|
||||
var langMain = _.first(lang.split("-"));
|
||||
var langSecond = _.last(lang.split("-"));
|
||||
|
||||
var localeMain = _.first(locale.split("-"));
|
||||
var localeSecond = _.last(locale.split("-"));
|
||||
var localeMain = _.first(locale.split("-"));
|
||||
var localeSecond = _.last(locale.split("-"));
|
||||
|
||||
if (locale == lang) return 100;
|
||||
if (localeMain == langMain) return 50;
|
||||
if (localeSecond == langSecond) return 20;
|
||||
return 0;
|
||||
if (locale == lang) return 100;
|
||||
if (localeMain == langMain) return 50;
|
||||
if (localeSecond == langSecond) return 20;
|
||||
return 0;
|
||||
};
|
||||
|
||||
var normalizeLanguage = _.memoize(function(lang) {
|
||||
var locales = getLocales();
|
||||
var language = _.chain(locales)
|
||||
.values()
|
||||
.map(function(locale) {
|
||||
locale = locale.id;
|
||||
var locales = getLocales();
|
||||
var language = _.chain(locales)
|
||||
.values()
|
||||
.map(function(locale) {
|
||||
locale = locale.id;
|
||||
|
||||
return {
|
||||
locale: locale,
|
||||
score: compareLocales(lang, locale)
|
||||
}
|
||||
})
|
||||
.filter(function(lang) {
|
||||
return lang.score > 0;
|
||||
})
|
||||
.sortBy("score")
|
||||
.pluck("locale")
|
||||
.last()
|
||||
.value();
|
||||
return language || lang;
|
||||
return {
|
||||
locale: locale,
|
||||
score: compareLocales(lang, locale)
|
||||
}
|
||||
})
|
||||
.filter(function(lang) {
|
||||
return lang.score > 0;
|
||||
})
|
||||
.sortBy("score")
|
||||
.pluck("locale")
|
||||
.last()
|
||||
.value();
|
||||
return language || lang;
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
getLocales: getLocales,
|
||||
getLanguages: getLanguages,
|
||||
getByLanguage: getByLanguage,
|
||||
normalizeLanguage: normalizeLanguage
|
||||
getLocales: getLocales,
|
||||
getLanguages: getLanguages,
|
||||
getByLanguage: getByLanguage,
|
||||
normalizeLanguage: normalizeLanguage
|
||||
};
|
||||
|
||||
+17
-16
@@ -1,38 +1,39 @@
|
||||
var _ = require("lodash");
|
||||
var Q = require("q");
|
||||
var fs = require("./fs");
|
||||
var exec = require('child_process').exec;
|
||||
var spawn = require('spawn-cmd').spawn;
|
||||
|
||||
var links = require("./links");
|
||||
|
||||
// Convert a svg file
|
||||
var convertSVG = function(source, dest, options) {
|
||||
if (!fs.existsSync(source)) return Q.reject(new Error("File doesn't exist: "+source));
|
||||
if (!fs.existsSync(source)) return Q.reject(new Error("File doesn't exist: "+source));
|
||||
var d = Q.defer();
|
||||
|
||||
var d = Q.defer();
|
||||
options = _.defaults(options || {}, {
|
||||
|
||||
options = _.defaults(options || {}, {
|
||||
});
|
||||
|
||||
});
|
||||
//var command = shellescape(['svgexport', source, dest]);
|
||||
var child = spawn('svgexport', [source, dest]);
|
||||
|
||||
var command = "svgexport "+source+" "+dest;
|
||||
child.on("error", function(error) {
|
||||
if (error.code == "ENOENT") error = new Error("Need to install 'svgexport' using 'npm install svgexport -g'");
|
||||
return d.reject(error);
|
||||
});
|
||||
|
||||
var child = exec(command, function (error, stdout, stderr) {
|
||||
if (error) {
|
||||
if (error.code == 127) error = new Error("Need to install 'svgexport' using 'npm install svgexport -g'");
|
||||
return d.reject(error);
|
||||
}
|
||||
if (fs.existsSync(dest)) {
|
||||
child.on("close", function(code) {
|
||||
if (code == 0 && fs.existsSync(dest)) {
|
||||
d.resolve();
|
||||
} else {
|
||||
d.reject(new Error("Error converting "+source));
|
||||
d.reject(new Error("Error converting "+source+" into "+dest));
|
||||
}
|
||||
});
|
||||
|
||||
return d.promise;
|
||||
return d.promise;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
convertSVG: convertSVG,
|
||||
INVALID: [".svg"]
|
||||
convertSVG: convertSVG,
|
||||
INVALID: [".svg"]
|
||||
};
|
||||
|
||||
+21
-8
@@ -15,12 +15,27 @@ var isRelative = function(href) {
|
||||
try {
|
||||
var parsed = url.parse(href);
|
||||
|
||||
return !!(!parsed.protocol && parsed.path);// && parsed.path[0] != '/';
|
||||
return !!(!parsed.protocol && parsed.path);
|
||||
} catch(err) {}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// Return true if the link is an achor
|
||||
var isAnchor = function(href) {
|
||||
try {
|
||||
var parsed = url.parse(href);
|
||||
return !!(!parsed.protocol && !parsed.path && parsed.hash);
|
||||
} catch(err) {}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
// Normalize a path to be a link
|
||||
var normalizeLink = function(s) {
|
||||
return s.replace(/\\/g, '/');
|
||||
};
|
||||
|
||||
// Relative to absolute path
|
||||
// dir: directory parent of the file currently in rendering process
|
||||
// outdir: directory parent from the html output
|
||||
@@ -36,7 +51,7 @@ var toAbsolute = function(_href, dir, outdir) {
|
||||
_href = path.relative(outdir, hrefInRoot);
|
||||
|
||||
// Normalize windows paths
|
||||
_href = _href.replace(/\\/g, '/');
|
||||
_href = normalizeLink(_href);
|
||||
|
||||
return _href;
|
||||
};
|
||||
@@ -45,11 +60,7 @@ var toAbsolute = function(_href, dir, outdir) {
|
||||
var join = function() {
|
||||
var _href = path.join.apply(path, arguments);
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
_href = _href.replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
return _href;
|
||||
return normalizeLink(_href);
|
||||
};
|
||||
|
||||
// Change extension
|
||||
@@ -61,9 +72,11 @@ var changeExtension = function(filename, newext) {
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
isAnchor: isAnchor,
|
||||
isRelative: isRelative,
|
||||
isExternal: isExternal,
|
||||
toAbsolute: toAbsolute,
|
||||
join: join,
|
||||
changeExtension: changeExtension
|
||||
changeExtension: changeExtension,
|
||||
normalize: normalizeLink
|
||||
};
|
||||
|
||||
+75
-75
@@ -3,100 +3,100 @@ var util = require('util');
|
||||
var color = require('bash-color');
|
||||
|
||||
var LEVELS = {
|
||||
DEBUG: 0,
|
||||
INFO: 1,
|
||||
WARN: 2,
|
||||
ERROR: 3,
|
||||
DISABLED: 10
|
||||
DEBUG: 0,
|
||||
INFO: 1,
|
||||
WARN: 2,
|
||||
ERROR: 3,
|
||||
DISABLED: 10
|
||||
};
|
||||
|
||||
var COLORS = {
|
||||
DEBUG: color.purple,
|
||||
INFO: color.cyan,
|
||||
WARN: color.yellow,
|
||||
ERROR: color.red
|
||||
DEBUG: color.purple,
|
||||
INFO: color.cyan,
|
||||
WARN: color.yellow,
|
||||
ERROR: color.red
|
||||
};
|
||||
|
||||
module.exports = function(_write, logLevel) {
|
||||
var logger = {};
|
||||
var lastChar = '\n';
|
||||
if (_.isString(logLevel)) logLevel = LEVELS[logLevel.toUpperCase()];
|
||||
var logger = {};
|
||||
var lastChar = '\n';
|
||||
if (_.isString(logLevel)) logLevel = LEVELS[logLevel.toUpperCase()];
|
||||
|
||||
// Write a simple message
|
||||
logger.write = function(msg) {
|
||||
msg = msg.toString();
|
||||
lastChar = _.last(msg);
|
||||
return _write(msg);
|
||||
};
|
||||
// Write a simple message
|
||||
logger.write = function(msg) {
|
||||
msg = msg.toString();
|
||||
lastChar = _.last(msg);
|
||||
return _write(msg);
|
||||
};
|
||||
|
||||
// Format a message
|
||||
logger.format = function() {
|
||||
return util.format.apply(util, arguments);
|
||||
};
|
||||
// Format a message
|
||||
logger.format = function() {
|
||||
return util.format.apply(util, arguments);
|
||||
};
|
||||
|
||||
// Write a line
|
||||
logger.writeLn = function(msg) {
|
||||
return this.write((msg || "")+"\n");
|
||||
};
|
||||
// Write a line
|
||||
logger.writeLn = function(msg) {
|
||||
return this.write((msg || "")+"\n");
|
||||
};
|
||||
|
||||
// Write a message with a certain level
|
||||
logger.log = function(level) {
|
||||
if (level < logLevel) return;
|
||||
// Write a message with a certain level
|
||||
logger.log = function(level) {
|
||||
if (level < logLevel) return;
|
||||
|
||||
var levelKey = _.findKey(LEVELS, function(v) { return v == level; });
|
||||
var args = Array.prototype.slice.apply(arguments, [1]);
|
||||
var msg = logger.format.apply(logger, args);
|
||||
var levelKey = _.findKey(LEVELS, function(v) { return v == level; });
|
||||
var args = Array.prototype.slice.apply(arguments, [1]);
|
||||
var msg = logger.format.apply(logger, args);
|
||||
|
||||
if (lastChar == '\n') {
|
||||
msg = COLORS[levelKey](levelKey.toLowerCase()+":")+" "+msg;
|
||||
}
|
||||
if (lastChar == '\n') {
|
||||
msg = COLORS[levelKey](levelKey.toLowerCase()+":")+" "+msg;
|
||||
}
|
||||
|
||||
return logger.write(msg);
|
||||
};
|
||||
logger.logLn = function() {
|
||||
if (lastChar != '\n') logger.write("\n");
|
||||
return logger.write(msg);
|
||||
};
|
||||
logger.logLn = function() {
|
||||
if (lastChar != '\n') logger.write("\n");
|
||||
|
||||
var args = Array.prototype.slice.apply(arguments);
|
||||
args.push("\n");
|
||||
logger.log.apply(logger, args);
|
||||
};
|
||||
var args = Array.prototype.slice.apply(arguments);
|
||||
args.push("\n");
|
||||
logger.log.apply(logger, args);
|
||||
};
|
||||
|
||||
// Write a OK
|
||||
logger.ok = function(level) {
|
||||
var args = Array.prototype.slice.apply(arguments, [1]);
|
||||
var msg = logger.format.apply(logger, args);
|
||||
if (arguments.length > 1) {
|
||||
logger.logLn(level, color.green('>> ') + msg.trim().replace(/\n/g, color.green('\n>> ')));
|
||||
} else {
|
||||
logger.log(level, color.green("OK"), "\n");
|
||||
}
|
||||
};
|
||||
// Write a OK
|
||||
logger.ok = function(level) {
|
||||
var args = Array.prototype.slice.apply(arguments, [1]);
|
||||
var msg = logger.format.apply(logger, args);
|
||||
if (arguments.length > 1) {
|
||||
logger.logLn(level, color.green('>> ') + msg.trim().replace(/\n/g, color.green('\n>> ')));
|
||||
} else {
|
||||
logger.log(level, color.green("OK"), "\n");
|
||||
}
|
||||
};
|
||||
|
||||
// Write an "FAIL"
|
||||
logger.fail = function(level) {
|
||||
return logger.log(level, color.red("ERROR")+"\n");
|
||||
};
|
||||
// Write an "FAIL"
|
||||
logger.fail = function(level) {
|
||||
return logger.log(level, color.red("ERROR")+"\n");
|
||||
};
|
||||
|
||||
_.each(_.omit(LEVELS, 'DISABLED'), function(level, levelKey) {
|
||||
levelKey = levelKey.toLowerCase();
|
||||
_.each(_.omit(LEVELS, 'DISABLED'), function(level, levelKey) {
|
||||
levelKey = levelKey.toLowerCase();
|
||||
|
||||
logger[levelKey] = _.partial(logger.log, level);
|
||||
logger[levelKey].ln = _.partial(logger.logLn, level);
|
||||
logger[levelKey].ok = _.partial(logger.ok, level);
|
||||
logger[levelKey].fail = _.partial(logger.fail, level);
|
||||
logger[levelKey].promise = function(p) {
|
||||
return p.
|
||||
then(function(st) {
|
||||
logger[levelKey].ok();
|
||||
return st;
|
||||
}, function(err) {
|
||||
logger[levelKey].fail();
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
});
|
||||
logger[levelKey] = _.partial(logger.log, level);
|
||||
logger[levelKey].ln = _.partial(logger.logLn, level);
|
||||
logger[levelKey].ok = _.partial(logger.ok, level);
|
||||
logger[levelKey].fail = _.partial(logger.fail, level);
|
||||
logger[levelKey].promise = function(p) {
|
||||
return p.
|
||||
then(function(st) {
|
||||
logger[levelKey].ok();
|
||||
return st;
|
||||
}, function(err) {
|
||||
logger[levelKey].fail();
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return logger;
|
||||
return logger;
|
||||
};
|
||||
module.exports.LEVELS = LEVELS;
|
||||
module.exports.COLORS = COLORS;
|
||||
|
||||
@@ -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,
|
||||
|
||||
+47
-10
@@ -1,5 +1,6 @@
|
||||
var Q = require('q');
|
||||
var _ = require('lodash');
|
||||
var url = require('url');
|
||||
var path = require('path');
|
||||
var cheerio = require('cheerio');
|
||||
var domSerializer = require('dom-serializer');
|
||||
@@ -10,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) {
|
||||
@@ -104,7 +106,7 @@ function normalizeHtml(src, options) {
|
||||
// Generate filename
|
||||
dest = "/"+fs.getUniqueFilename(outputRoot, dest);
|
||||
|
||||
svgContent[dest] = content;
|
||||
svgContent[dest] = '<?xml version="1.0" encoding="UTF-8"?>'+content;
|
||||
$(this).replaceWith($("<img>").attr("src", dest));
|
||||
});
|
||||
}
|
||||
@@ -132,7 +134,7 @@ function normalizeHtml(src, options) {
|
||||
}
|
||||
|
||||
var ext = path.extname(src);
|
||||
var srcAbs = path.join("/", options.base, src);
|
||||
var srcAbs = links.join("/", options.base, src);
|
||||
|
||||
// Test image extension
|
||||
if (_.contains(imgUtils.INVALID, ext)) {
|
||||
@@ -144,7 +146,7 @@ function normalizeHtml(src, options) {
|
||||
var dest = "";
|
||||
|
||||
// Replace extension
|
||||
dest = path.join(path.dirname(srcAbs), path.basename(srcAbs, ext)+".png");
|
||||
dest = links.join(path.dirname(srcAbs), path.basename(srcAbs, ext)+".png");
|
||||
dest = dest[0] == "/"? dest.slice(1) : dest;
|
||||
|
||||
// Get a name that doesn't exists
|
||||
@@ -163,7 +165,7 @@ function normalizeHtml(src, options) {
|
||||
dest: path.join("./", dest)
|
||||
});
|
||||
|
||||
src = path.join("/", dest);
|
||||
src = links.join("/", dest);
|
||||
}
|
||||
|
||||
// Reset as relative to output
|
||||
@@ -182,19 +184,27 @@ function normalizeHtml(src, options) {
|
||||
$(this).attr("src", src);
|
||||
});
|
||||
|
||||
// Normalize links
|
||||
$("a").each(function() {
|
||||
var href = $(this).attr("href");
|
||||
if (!href) return;
|
||||
|
||||
if (links.isRelative(href)) {
|
||||
var absolutePath = path.join(options.base, href);
|
||||
if (links.isAnchor(href)) {
|
||||
// Keep it as it is
|
||||
} else if (links.isRelative(href)) {
|
||||
var parts = url.parse(href);
|
||||
var absolutePath = path.join(options.base, parts.pathname);
|
||||
var anchor = parts.hash || "";
|
||||
|
||||
// If is in navigation relative: change extsnio nto be .html
|
||||
if (options.navigation[absolutePath]) href = links.changeExtension(href, ".html");
|
||||
// If is in navigation relative: transform as content
|
||||
if (options.navigation[absolutePath]) {
|
||||
absolutePath = options.book.contentLink(absolutePath);
|
||||
}
|
||||
|
||||
// Transform as absolute
|
||||
href = links.toAbsolute(href, options.base, options.output);
|
||||
href = links.toAbsolute("/"+absolutePath, options.base, options.output)+anchor;
|
||||
} else {
|
||||
// External links
|
||||
$(this).attr("target", "_blank");
|
||||
}
|
||||
|
||||
@@ -202,12 +212,39 @@ function normalizeHtml(src, options) {
|
||||
$(this).attr("href", href);
|
||||
});
|
||||
|
||||
// Replace glossayr terms
|
||||
// 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
|
||||
_.each(options.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"], 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);
|
||||
|
||||
+12
-9
@@ -1,25 +1,25 @@
|
||||
{
|
||||
"name": "gitbook",
|
||||
"version": "2.0.0-alpha.9",
|
||||
"version": "2.0.0",
|
||||
"homepage": "https://www.gitbook.com",
|
||||
"description": "Library and cmd utility to generate GitBooks",
|
||||
"main": "lib/index.js",
|
||||
"dependencies": {
|
||||
"q": "1.0.1",
|
||||
"lunr": "0.5.7",
|
||||
"lodash": "3.2.0",
|
||||
"lodash": "3.5.0",
|
||||
"graceful-fs": "3.0.5",
|
||||
"resolve": "0.6.3",
|
||||
"fs-extra": "0.16.3",
|
||||
"fs-extra": "0.16.5",
|
||||
"fstream-ignore": "1.0.2",
|
||||
"gitbook-parsers": "0.4.1",
|
||||
"nunjucks": "git+https://github.com/mozilla/nunjucks.git#42d2b9f5c0ad5db8ca3a1fdbba5bde9fc4cc2c45",
|
||||
"gitbook-parsers": "0.7.2",
|
||||
"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",
|
||||
"npmi": "0.1.1",
|
||||
"cheerio": "0.18.0",
|
||||
"cheerio": "0.19.0",
|
||||
"gitbook-plugin-livereload": "0.0.1",
|
||||
"gaze": "~0.5.1",
|
||||
"send": "0.2.0",
|
||||
@@ -30,10 +30,13 @@
|
||||
"URIjs": "1.14.1",
|
||||
"request": "2.51.0",
|
||||
"npm": "2.4.1",
|
||||
"dom-serializer": "0.1.0"
|
||||
"dom-serializer": "0.1.0",
|
||||
"spawn-cmd": "0.0.2",
|
||||
"highlight.js": "8.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "1.18.2",
|
||||
"mocha": "2.2.1",
|
||||
"should": "5.2.0",
|
||||
"grunt": "~0.4.2",
|
||||
"grunt-cli": "0.1.11",
|
||||
"grunt-contrib-copy": "0.5.0",
|
||||
@@ -42,7 +45,7 @@
|
||||
"grunt-bower-install-simple": "0.9.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "export TESTING=true; mocha --reporter list --timeout 15000"
|
||||
"test": "node_modules/.bin/mocha --reporter spec --timeout 15000"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
var _ = require('lodash');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var should = require('should');
|
||||
var cheerio = require('cheerio');
|
||||
|
||||
should.Assertion.add('file', function(file, description) {
|
||||
this.params = { actual: this.obj.toString(), operator: 'have file ' + file, message: description };
|
||||
|
||||
this.obj.should.have.property('options').which.is.an.Object;
|
||||
this.obj.options.should.have.property('output').which.is.a.String;
|
||||
this.assert(fs.existsSync(path.resolve(this.obj.options.output, file)));
|
||||
});
|
||||
|
||||
should.Assertion.add('jsonfile', function(file, description) {
|
||||
this.params = { actual: this.obj.toString(), operator: 'have valid jsonfile ' + file, message: description };
|
||||
|
||||
this.obj.should.have.property('options').which.is.an.Object;
|
||||
this.obj.options.should.have.property('output').which.is.a.String;
|
||||
this.assert(JSON.parse(fs.readFileSync(path.resolve(this.obj.options.output, file), { encoding: "utf-8" })));
|
||||
});
|
||||
|
||||
should.Assertion.add('html', function(rules, description) {
|
||||
this.params = { actual: "HTML string", operator: 'valid html', message: description };
|
||||
var $ = cheerio.load(this.obj);
|
||||
|
||||
_.each(rules, function(validations, query) {
|
||||
validations = _.defaults(validations || {}, {
|
||||
count: 1,
|
||||
attributes: {},
|
||||
trim: false,
|
||||
text: undefined
|
||||
});
|
||||
|
||||
var $el = $(query);
|
||||
|
||||
// Test number of elements
|
||||
$el.should.have.lengthOf(validations.count);
|
||||
|
||||
// Test text
|
||||
if (validations.text !== undefined) {
|
||||
var text = $el.text();
|
||||
if (validations.trim) text = text.trim();
|
||||
text.should.be.equal(validations.text);
|
||||
}
|
||||
|
||||
// Test attributes
|
||||
_.each(validations.attributes, function(value, name) {
|
||||
$el.attr(name).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,9 @@
|
||||
# Glossary
|
||||
|
||||
## test
|
||||
|
||||
Just a simple and easy to understand test.
|
||||
|
||||
## hakunamatata
|
||||
|
||||
This word is not present in the content.
|
||||
@@ -0,0 +1,8 @@
|
||||
# Readme
|
||||
|
||||
The word test should be replaced by a glossary link.
|
||||
|
||||
```
|
||||
But the word test should not be replaced in code blocks
|
||||
```
|
||||
|
||||
@@ -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
|
||||

|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
|
||||
<svg version="1.1" baseProfile="tiny" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg-root" width="100%" height="100%" viewBox="0 0 480 360">
|
||||
<title id="test-title">basic SVG tiny doc</title>
|
||||
<g id="test-body-content">
|
||||
<text font-family="Arial" font-size="14" text-anchor="middle" x="225" y="25">hello world</text>
|
||||
</g>
|
||||
<text id="revision" x="10" y="340" font-size="40" stroke="none" fill="black">Revision: 1.1</text>
|
||||
<rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000000"/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 730 B |
@@ -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 @@
|
||||
# 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
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
+17
-29
@@ -1,36 +1,24 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var _ = require('lodash');
|
||||
var assert = require('assert');
|
||||
var cheerio = require('cheerio');
|
||||
|
||||
var fs = require("fs");
|
||||
var fsUtil = require("../lib/utils/fs");
|
||||
describe('eBook generator', function () {
|
||||
describe('Basic Book', function() {
|
||||
var book;
|
||||
|
||||
before(function() {
|
||||
return books.generate("basic", "ebook")
|
||||
.then(function(_book) {
|
||||
book = _book;
|
||||
});
|
||||
});
|
||||
|
||||
describe('eBook Generator', function () {
|
||||
it('should correctly generate ebook pages', function(done) {
|
||||
testGeneration(books[1], "ebook", function(output) {
|
||||
assert(fs.existsSync(path.join(output, "SUMMARY.html")));
|
||||
}, done);
|
||||
});
|
||||
it('should correctly output a SUMMARY.html', function() {
|
||||
book.should.have.file("SUMMARY.html");
|
||||
});
|
||||
|
||||
it('should correctly convert svg images to png', function(done) {
|
||||
testGeneration(books[4], "ebook", function(output) {
|
||||
// Check that all images exists
|
||||
_.each([
|
||||
"index.html",
|
||||
"sub/PAGE.html"
|
||||
], function(pageName) {
|
||||
var pageFile = path.join(output, pageName);
|
||||
var pageFolder = path.dirname(pageFile);
|
||||
var pageContent = fs.readFileSync(pageFile, {encoding: "utf8"});
|
||||
var $ = cheerio.load(pageContent);
|
||||
|
||||
$("img").each(function() {
|
||||
var src = $(this).attr("src");
|
||||
assert(fs.existsSync(path.resolve(pageFolder, src)), src+" not found for page "+pageName);
|
||||
})
|
||||
});
|
||||
}, done);
|
||||
it('should correctly copy assets', function() {
|
||||
book.should.have.file("gitbook");
|
||||
book.should.have.file("gitbook/style.css");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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
-11
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
|
||||
<svg version="1.1" baseProfile="tiny" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg-root" width="100%" height="100%" viewBox="0 0 480 360">
|
||||
<title id="test-title">basic SVG tiny doc</title>
|
||||
<g id="test-body-content">
|
||||
<text font-family="Arial" font-size="14" text-anchor="middle" x="225" y="25">hello world</text>
|
||||
</g>
|
||||
<text id="revision" x="10" y="340" font-size="40" stroke="none" fill="black">Revision: 1.1</text>
|
||||
<rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000000"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 709 B |
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");
|
||||
});
|
||||
});
|
||||
|
||||
+69
-26
@@ -1,35 +1,78 @@
|
||||
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(2);
|
||||
});
|
||||
});
|
||||
|
||||
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
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+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
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
+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("intro.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");
|
||||
});
|
||||
});
|
||||
});
|
||||
+20
-16
@@ -1,33 +1,37 @@
|
||||
var path = require('path');
|
||||
var _ = require('lodash');
|
||||
var assert = require('assert');
|
||||
|
||||
var should = require('should');
|
||||
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 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");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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, "Introduction");
|
||||
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, "Introduction");
|
||||
assert.equal(NAVIGATION["sub/test1.md"].next, null);
|
||||
});
|
||||
});
|
||||
+133
-132
@@ -1,189 +1,190 @@
|
||||
var path = require('path');
|
||||
var _ = require('lodash');
|
||||
var assert = require('assert');
|
||||
var fs = require("fs");
|
||||
var should = require('should');
|
||||
var path = require('path');
|
||||
|
||||
var Plugin = require("../lib/plugin");
|
||||
|
||||
var PLUGINS_ROOT = path.resolve(__dirname, "plugins");
|
||||
var Plugin = require('../lib/plugin');
|
||||
var PLUGINS_ROOT = path.resolve(__dirname, 'plugins');
|
||||
|
||||
describe('Plugins', function () {
|
||||
describe('invalid plugin', function() {
|
||||
it('should signal as invalid', function() {
|
||||
var plugin = new Plugin(books[0], "invalid");
|
||||
var book;
|
||||
|
||||
before(function() {
|
||||
return books.parse("basic")
|
||||
.then(function(_book) {
|
||||
book = _book;
|
||||
});
|
||||
});
|
||||
|
||||
describe('Invalid', function() {
|
||||
var plugin;
|
||||
|
||||
before(function() {
|
||||
plugin = new Plugin(book, "invalid");
|
||||
plugin.load("./invalid", PLUGINS_ROOT);
|
||||
assert(!plugin.isValid());
|
||||
});
|
||||
|
||||
it('should be detected', function() {
|
||||
should(plugin.isValid()).be.exactly(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('empty plugin', function() {
|
||||
var plugin = new Plugin(books[0], "invalid");
|
||||
plugin.load("./empty", PLUGINS_ROOT);
|
||||
describe('Empty', function() {
|
||||
var plugin;
|
||||
|
||||
it('should valid a plugin', function() {
|
||||
assert(plugin.isValid());
|
||||
before(function() {
|
||||
plugin = new Plugin(book, "empty");
|
||||
plugin.load("./empty", PLUGINS_ROOT);
|
||||
});
|
||||
|
||||
it('should return an empty list of resources', function(done) {
|
||||
qdone(
|
||||
plugin.getResources()
|
||||
.then(function(resources) {
|
||||
_.each(Plugin.RESOURCES, function(resName) {
|
||||
assert.equal(resources[resName].length, 0);
|
||||
it('should valid a plugin', function() {
|
||||
should(plugin.isValid()).be.exactly(true);
|
||||
});
|
||||
|
||||
it('should return an empty list of resources', function() {
|
||||
return plugin.getResources()
|
||||
.then(function(resources) {
|
||||
_.each(Plugin.RESOURCES, function(resName) {
|
||||
resources[resName].should.have.lengthOf(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Resources', function() {
|
||||
var plugin;
|
||||
|
||||
before(function() {
|
||||
plugin = new Plugin(book, "resources");
|
||||
plugin.load("./resources", PLUGINS_ROOT);
|
||||
|
||||
return book.plugins.load(plugin);
|
||||
});
|
||||
|
||||
it('should valid a plugin', function() {
|
||||
should(plugin.isValid()).be.exactly(true);
|
||||
});
|
||||
|
||||
describe('Website', function() {
|
||||
it('should return a valid list of resources', function() {
|
||||
return plugin.getResources("website")
|
||||
.then(function(resources) {
|
||||
resources["js"].should.have.lengthOf(1);
|
||||
});
|
||||
}),
|
||||
done);
|
||||
});
|
||||
|
||||
it('should extend books plugins', function() {
|
||||
var resources = book.plugins.resources("website");
|
||||
resources["js"].should.have.lengthOf(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('eBook', function() {
|
||||
it('should return a valid list of resources', function() {
|
||||
return plugin.getResources("ebook")
|
||||
.then(function(resources) {
|
||||
resources["css"].should.have.lengthOf(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('should extend books plugins', function() {
|
||||
var resources = book.plugins.resources("ebook");
|
||||
resources["css"].should.have.lengthOf(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('resources plugin', function() {
|
||||
var plugin = new Plugin(books[0], "resources");
|
||||
plugin.load("./resources", PLUGINS_ROOT);
|
||||
describe('Filters', function() {
|
||||
var plugin;
|
||||
|
||||
before(function(done) {
|
||||
qdone(books[0].plugins.load(plugin), done);
|
||||
before(function() {
|
||||
plugin = new Plugin(book, "filters");
|
||||
plugin.load("./filters", PLUGINS_ROOT);
|
||||
|
||||
return book.plugins.load(plugin);
|
||||
});
|
||||
|
||||
it('should valid a plugin', function() {
|
||||
assert(plugin.isValid());
|
||||
});
|
||||
|
||||
it('should return a valid list of resources (website)', function(done) {
|
||||
qdone(
|
||||
plugin.getResources("website")
|
||||
.then(function(resources) {
|
||||
assert.equal(resources["js"].length, 1);
|
||||
}),
|
||||
done);
|
||||
});
|
||||
|
||||
it('should return a valid list of resources (ebook)', function(done) {
|
||||
qdone(
|
||||
plugin.getResources("ebook")
|
||||
.then(function(resources) {
|
||||
assert.equal(resources["css"].length, 1);
|
||||
}),
|
||||
done);
|
||||
});
|
||||
|
||||
it('should extend books plugins (website)', function() {
|
||||
var resources = books[0].plugins.resources("website");
|
||||
assert.equal(resources["js"].length, 1);
|
||||
});
|
||||
|
||||
it('should extend books plugins (ebook)', function() {
|
||||
var resources = books[0].plugins.resources("ebook");
|
||||
assert.equal(resources["css"].length, 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('filters', function() {
|
||||
var plugin = new Plugin(books[0], "filters");
|
||||
plugin.load("./filters", PLUGINS_ROOT);
|
||||
|
||||
before(function(done) {
|
||||
qdone(books[0].plugins.load(plugin), done);
|
||||
});
|
||||
|
||||
it('should valid a plugin', function() {
|
||||
assert(plugin.isValid());
|
||||
should(plugin.isValid()).be.exactly(true);
|
||||
});
|
||||
|
||||
it('should return a map of filters', function() {
|
||||
var filters = plugin.getFilters();
|
||||
assert.equal(_.size(filters), 2);
|
||||
assert(filters["hello"]);
|
||||
assert(filters["helloCtx"]);
|
||||
|
||||
_.size(filters).should.equal(2);
|
||||
filters.should.have.property("hello");
|
||||
filters.should.have.property("helloCtx");
|
||||
});
|
||||
|
||||
it('should correctly extend template filters', function(done) {
|
||||
qdone(
|
||||
books[0].template.renderString('{{ "World"|hello }}')
|
||||
it('should correctly extend template filters', function() {
|
||||
return book.template.renderString('{{ "World"|hello }}')
|
||||
.then(function(content) {
|
||||
assert.equal(content, "Hello World");
|
||||
}),
|
||||
done
|
||||
);
|
||||
content.should.equal("Hello World");
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly set book as context', function(done) {
|
||||
qdone(
|
||||
books[0].template.renderString('{{ "root"|helloCtx }}')
|
||||
it('should correctly set book as context', function() {
|
||||
return book.template.renderString('{{ "root"|helloCtx }}')
|
||||
.then(function(content) {
|
||||
assert.equal(content, "root:"+books[0].root);
|
||||
}),
|
||||
done
|
||||
);
|
||||
content.should.equal("root:"+book.root);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('blocks', function() {
|
||||
var plugin = new Plugin(books[0], "blocks");
|
||||
plugin.load("./blocks", PLUGINS_ROOT);
|
||||
describe('Blocks', function() {
|
||||
var plugin;
|
||||
|
||||
before(function() {
|
||||
plugin = new Plugin(book, "blocks");
|
||||
plugin.load("./blocks", PLUGINS_ROOT);
|
||||
|
||||
return book.plugins.load(plugin);
|
||||
});
|
||||
|
||||
var testTpl = function(str, args, options) {
|
||||
return books[0].template.renderString(str, args, options)
|
||||
.then(books[0].template.postProcess)
|
||||
return book.template.renderString(str, args, options)
|
||||
.then(book.template.postProcess)
|
||||
};
|
||||
|
||||
before(function(done) {
|
||||
qdone(books[0].plugins.load(plugin), done);
|
||||
});
|
||||
|
||||
it('should valid a plugin', function() {
|
||||
assert(plugin.isValid());
|
||||
should(plugin.isValid()).be.exactly(true);
|
||||
});
|
||||
|
||||
it('should correctly extend template blocks', function(done) {
|
||||
qdone(
|
||||
testTpl('{% test %}hello{% endtest %}')
|
||||
it('should correctly extend template blocks', function() {
|
||||
return testTpl('{% test %}hello{% endtest %}')
|
||||
.then(function(content) {
|
||||
assert.equal(content, "testhellotest");
|
||||
}),
|
||||
done
|
||||
);
|
||||
content.should.equal("testhellotest");
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly accept shortcuts', function(done) {
|
||||
qdone(
|
||||
testTpl('$$hello$$', {}, {
|
||||
it('should correctly accept shortcuts', function() {
|
||||
return testTpl('$$hello$$', {}, {
|
||||
type: "markdown"
|
||||
})
|
||||
.then(function(content) {
|
||||
assert.equal(content, "testhellotest");
|
||||
}),
|
||||
done
|
||||
);
|
||||
content.should.equal("testhellotest");
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly extend template blocks with defined end', function(done) {
|
||||
qdone(
|
||||
testTpl('{% test2 %}hello{% endtest2end %}')
|
||||
it('should correctly extend template blocks with defined end', function() {
|
||||
return testTpl('{% test2 %}hello{% endtest2end %}')
|
||||
.then(function(content) {
|
||||
assert.equal(content, "test2hellotest2");
|
||||
}),
|
||||
done
|
||||
);
|
||||
content.should.equal("test2hellotest2");
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly extend template blocks with sub-blocks', function(done) {
|
||||
qdone(
|
||||
testTpl('{% test3join separator=";" %}hello{% also %}world{% endtest3join %}')
|
||||
it('should correctly extend template blocks with sub-blocks', function() {
|
||||
return testTpl('{% test3join separator=";" %}hello{% also %}world{% endtest3join %}')
|
||||
.then(function(content) {
|
||||
assert.equal(content, "hello;world");
|
||||
}),
|
||||
done
|
||||
);
|
||||
content.should.equal("hello;world");
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly extend template blocks with different sub-blocks', function(done) {
|
||||
qdone(
|
||||
testTpl('{% test4join separator=";" %}hello{% also %}the{% finally %}world{% endtest4join %}')
|
||||
it('should correctly extend template blocks with different sub-blocks', function() {
|
||||
return testTpl('{% test4join separator=";" %}hello{% also %}the{% finally %}world{% endtest4join %}')
|
||||
.then(function(content) {
|
||||
assert.equal(content, "hello;the;world");
|
||||
}),
|
||||
done
|
||||
);
|
||||
content.should.equal("hello;the;world");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -2,22 +2,22 @@ var assert = require("assert");
|
||||
|
||||
module.exports = {
|
||||
blocks: {
|
||||
"test": {
|
||||
"test": {
|
||||
shortcuts: {
|
||||
parsers: ["markdown"],
|
||||
start: "$$",
|
||||
end: "$$"
|
||||
},
|
||||
process: function(blk) {
|
||||
return "test"+blk.body+"test";
|
||||
}
|
||||
},
|
||||
"test2": {
|
||||
end: "endtest2end",
|
||||
process: function(blk) {
|
||||
return "test2"+blk.body+"test2";
|
||||
}
|
||||
},
|
||||
process: function(blk) {
|
||||
return "test"+blk.body+"test";
|
||||
}
|
||||
},
|
||||
"test2": {
|
||||
end: "endtest2end",
|
||||
process: function(blk) {
|
||||
return "test2"+blk.body+"test2";
|
||||
}
|
||||
},
|
||||
"test3join": {
|
||||
blocks: [
|
||||
"also"
|
||||
|
||||
@@ -4,7 +4,7 @@ module.exports = {
|
||||
return "Hello "+text;
|
||||
},
|
||||
helloCtx: function(text) {
|
||||
return text+":"+this.book.root;
|
||||
return text+":"+this.book.root;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,12 +1,12 @@
|
||||
module.exports = {
|
||||
website: {
|
||||
website: {
|
||||
js: [
|
||||
"https://cdn.mathjax.org/mathjax/2.4-latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
|
||||
]
|
||||
},
|
||||
ebook: {
|
||||
css: [
|
||||
"test"
|
||||
]
|
||||
css: [
|
||||
"test"
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
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");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
var pkg = require("../package.json");
|
||||
|
||||
describe('Templating', function () {
|
||||
var book;
|
||||
|
||||
before(function() {
|
||||
return books.parse("basic")
|
||||
.then(function(_book) {
|
||||
book = _book;
|
||||
});
|
||||
});
|
||||
|
||||
var testTpl = function(str, args, options) {
|
||||
return book.template.renderString(str, args, options)
|
||||
.then(book.template.postProcess)
|
||||
};
|
||||
|
||||
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() {
|
||||
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