mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-28 04:58:52 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| abbca568d1 | |||
| 40e49d0ac9 | |||
| 8d9a0a91f0 | |||
| 15640dfdf0 | |||
| 2f5dde5d2f | |||
| a9a8a04bca | |||
| c08e5ce62c | |||
| ec353e179d | |||
| 496f253e69 | |||
| e436115a4a | |||
| 1c61f93b5f | |||
| 0494f7d1fd | |||
| 4aa66338fc | |||
| 8cda844ef1 | |||
| dde1ef92f0 | |||
| 999f8b481f | |||
| 294951f22a |
+1
-1
@@ -28,7 +28,7 @@ build/Release
|
||||
*.swp
|
||||
|
||||
# Output of documentation
|
||||
docs/_book
|
||||
_book
|
||||
|
||||
book.pdf
|
||||
book.epub
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 3.x.x (unreleased)
|
||||
## 3.0.0 (pre)
|
||||
- Summary can contain external links and anchors (Fix [#776](https://github.com/GitbookIO/gitbook/issues/776))
|
||||
- Summary can contain differents entitled sections
|
||||
- Glossary is generated as a normal page
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
var pkg = require('../package.json');
|
||||
var pkg = require('./package.json');
|
||||
|
||||
module.exports = {
|
||||
root: './docs',
|
||||
title: 'GitBook Documentation',
|
||||
|
||||
plugins: ['theme-official'],
|
||||
+9
-9
@@ -9,25 +9,25 @@
|
||||
|
||||
* [Directory structure](structure.md)
|
||||
* [Pages and Summary](pages.md)
|
||||
* [Configuration](config.md)
|
||||
* [Glossary](lexicon.md)
|
||||
* [Multi-Lingual](languages.md)
|
||||
* [Configuration](config.md)
|
||||
* [AsciiDoc](asciidoc.md)
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
* [Templating](templating.md)
|
||||
* [Content References](conrefs.md)
|
||||
* [Variables](variables.md)
|
||||
|
||||
### Customization
|
||||
|
||||
* [Plugins](plugins.md)
|
||||
* [Theming](themes.md)
|
||||
* [Templating](templating/README.md)
|
||||
* [Content References](templating/conrefs.md)
|
||||
* [Variables](templating/variables.md)
|
||||
* [Plugins](plugins/README.md)
|
||||
* [Create a plugin](plugins/create.md)
|
||||
* [Test your plugin](plugins/testing.md)
|
||||
* [Theming](themes/README.md)
|
||||
|
||||
--
|
||||
|
||||
* [FAQ](faq.md)
|
||||
* [Examples](examples.md)
|
||||
* [Release notes](https://github.com/GitbookIO/gitbook/blob/master/CHANGES.md)
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ This file is used to define terms. [See the glossary section](./lexicon.md).
|
||||
Sufficiently advanced technology, beyond the understanding of the observer producing a sense of wonder.
|
||||
|
||||
== PHP
|
||||
An atrocious language, invented for the sole purpose of inflicting pain and suffering amongst the programming wizards of this world.
|
||||
A popular web programming language, used by many large websites such as Facebook. Rasmus Lerdorf originally created PHP in 1994 to power his personal homepage (PHP originally stood for "Personal Home Page" but now stands for "PHP: Hypertext Preprocessor").
|
||||
```
|
||||
|
||||
|
||||
|
||||
+5
-4
@@ -1,11 +1,12 @@
|
||||
# Configuration
|
||||
|
||||
GitBook allows you to customize your book using a flexible configuration. These options are specified in a `book.json` file.
|
||||
GitBook allows you to customize your book using a flexible configuration. These options are specified in a `book.json` file. For authors, not used to write JSON, you can validate the syntax using [jsonlint](http://jsonlint.com).
|
||||
|
||||
### Configuration Settings
|
||||
|
||||
| Variable | Description |
|
||||
| -------- | ----------- |
|
||||
| `root` | Path to the root folder containing the content |
|
||||
| `title` | Title of your book, default value is extracted from the README. On GitBook.com this field is pre-filled. |
|
||||
| `description` | Description of your book, default value is extracted from the README. On GitBook.com this field is pre-filled. |
|
||||
| `author` | Name of the author. On GitBook.com this field is pre-filled. |
|
||||
@@ -13,8 +14,8 @@ GitBook allows you to customize your book using a flexible configuration. These
|
||||
| `language` | ISO code of the book's language, default value is `en` |
|
||||
| `direction` | `rtl` or `ltr`, default value depends on the value of `language` |
|
||||
| `gitbook` | [SemVer](http://semver.org) condition to validate which GitBook version should be used |
|
||||
| `plugins` | List of plugins to load, See [the plugins section](plugins.md) for more details |
|
||||
| `pluginsConfig` |Configuration for plugins, See [the plugins section](plugins.md) for more details |
|
||||
| `plugins` | List of plugins to load, See [the plugins section](plugins/README.md) for more details |
|
||||
| `pluginsConfig` |Configuration for plugins, See [the plugins section](plugins/README.md) for more details |
|
||||
|
||||
### PDF Options
|
||||
|
||||
@@ -33,5 +34,5 @@ PDF Output can be customized using a set of options in the `book.json`:
|
||||
|
||||
### Plugins
|
||||
|
||||
Plugins and their configurations are specified in the `book.json`. See [the plugins section](plugins.md) for more details.
|
||||
Plugins and their configurations are specified in the `book.json`. See [the plugins section](plugins/README.md) for more details.
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
GitBook supports building books written in multiple languages. Each language should be a sub-directory following the normal GitBook format, and a file named `LANGS.md` should be present at the root of the repository with the following format:
|
||||
|
||||
```markdown
|
||||
# Languages
|
||||
|
||||
* [English](en/)
|
||||
* [French](fr/)
|
||||
* [Español](es/)
|
||||
|
||||
@@ -19,6 +19,8 @@ Once you find a plugin that you want to install, you need to add it to your `boo
|
||||
|
||||
You can also specify a specific version using: `"myPlugin@0.3.1"`. By default GitBook will resolve the latest version of the plugin compatbile with the current GitBook version.
|
||||
|
||||
### GitBook.com
|
||||
|
||||
Plugins are automatically installed on [GitBook.com](https://www.gitbook.com). Locally, run `gitbook install` to install and prepare all plugins for your books.
|
||||
|
||||
### Configuring plugins
|
||||
@@ -0,0 +1,63 @@
|
||||
# Create and publish a plugin
|
||||
|
||||
A GitBook plugin is a node package published on NPM that follow a defined convention.
|
||||
|
||||
## Structure
|
||||
|
||||
#### package.json
|
||||
|
||||
The `package.json` is a manifest format for describing **Node.js modules**. GitBook plugins are built on top of Node modules. It declares dependencies, version, ownership, and other information required to run a plugin in GitBook. This document describes the schema in detail.
|
||||
|
||||
```
|
||||
{
|
||||
"name": "gitbook-plugin-mytest",
|
||||
"version": "0.0.1",
|
||||
"description": "This is my first GitBook plugin",
|
||||
"engines": {
|
||||
"gitbook": ">1.x.x"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can learn more about `package.json` from the [NPM documentation](https://docs.npmjs.com/files/package.json).
|
||||
|
||||
The **package name** must begin with `gitbook-plugin-` and the **package engines** should contains `gitbook`.
|
||||
|
||||
#### index.js
|
||||
|
||||
The `index.js` is main entry point of your plugin runtime:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
// Map of hooks
|
||||
hooks: {},
|
||||
|
||||
// Map of new blocks
|
||||
blocks: {},
|
||||
|
||||
// Map of new filters
|
||||
filters: {}
|
||||
};
|
||||
```
|
||||
|
||||
## Publish your plugin
|
||||
|
||||
GitBook plugins can be published on [NPM](https://www.npmjs.com).
|
||||
|
||||
To publish a new plugin, you need to create an account on [npmjs.com](https://www.npmjs.com) then publish it from the command line:
|
||||
|
||||
```
|
||||
$ npm publish
|
||||
```
|
||||
|
||||
## Private plugins
|
||||
|
||||
Private plugins can be hosted on GitHub and included using `git` urls:
|
||||
|
||||
```
|
||||
{
|
||||
"plugins": [
|
||||
"myplugin@git+https://github.com/MyCompany/mygitbookplugin.git#1.0.0"
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,22 @@
|
||||
# Testing your plugin
|
||||
|
||||
### Testing your plugin locally
|
||||
|
||||
Testing your plugin on your book before plushing it is possible using [npm link](https://docs.npmjs.com/cli/link).
|
||||
|
||||
In the plugin's folder, run:
|
||||
|
||||
```
|
||||
$ npm link
|
||||
```
|
||||
|
||||
The nin your book's folder:
|
||||
|
||||
```
|
||||
$ npm link gitbook-plugin-<plugin's name>
|
||||
```
|
||||
|
||||
### Unit testing on Travis
|
||||
|
||||
[gitbook-tester](https://github.com/todvora/gitbook-tester) makes it easy to write **Node.js/Mocha** unit tests for your plugins. Using [Travis.org](https://travis.org), tests can be run on each commits/tags.
|
||||
|
||||
+26
-2
@@ -27,14 +27,38 @@ $ npm install gitbook-cli -g
|
||||
|
||||
`gitbook-cli` is an utility to install and use multiple versions of GitBook on the same system. It will automatically install the required version to build a book.
|
||||
|
||||
##### Using pre-releases
|
||||
##### Create a book
|
||||
|
||||
GitBook can setup a boilerplate book:
|
||||
|
||||
```
|
||||
$ gitbook init
|
||||
```
|
||||
|
||||
If you wish to create the book into a new directory, you can do so by running `gitbook init ./directory`
|
||||
|
||||
Preview and serve your book using:
|
||||
|
||||
```
|
||||
$ gitbook serve
|
||||
```
|
||||
|
||||
or build the static website using:
|
||||
|
||||
```
|
||||
$ gitbook build
|
||||
```
|
||||
|
||||
##### Install pre-releases
|
||||
|
||||
`gitbook-cli` makes it easy to install and test other versions of GitBook with your book:
|
||||
|
||||
```
|
||||
$ gitbook install beta
|
||||
$ gitbook fetch beta
|
||||
```
|
||||
|
||||
Use `gitbook ls-remote` to list remote versions available for install.
|
||||
|
||||
##### Debugging
|
||||
|
||||
You can use the options `--log=debug` and `--debug` to get better error messages (with stack trace). For example:
|
||||
|
||||
+7
-5
@@ -1,6 +1,6 @@
|
||||
# Directory structure
|
||||
|
||||
GitBook uses a very simple and obvious directory sttructure:
|
||||
GitBook uses a very simple and obvious directory structure:
|
||||
|
||||
```
|
||||
.
|
||||
@@ -45,18 +45,20 @@ bin/*
|
||||
|
||||
### Project documentation / Sub-directory {#subdirectory}
|
||||
|
||||
For project documentaiton, it sometimes better to use a diretcory (like `docs/`) to store the prject's documentation. You can use a `.gitbook` file to indicate to GitBook in which folder the book is stored:
|
||||
For software project, it sometimes better to use a diretcory (like `docs/`) to store the project's documentation. You can use the [`root` option](config.md) to indicate to GitBook in which folder the book is stored:
|
||||
|
||||
```
|
||||
.
|
||||
├── .gitbook
|
||||
├── book.json
|
||||
└── docs/
|
||||
├── README.md
|
||||
└── SUMMARY.md
|
||||
```
|
||||
|
||||
With `.gitbook` containing:
|
||||
With `book.json` containing:
|
||||
|
||||
```
|
||||
./docs/
|
||||
{
|
||||
"root": "./docs"
|
||||
}
|
||||
```
|
||||
|
||||
+17
-3
@@ -6,7 +6,6 @@ var location = require('../utils/location');
|
||||
var error = require('../utils/error');
|
||||
var BackboneFile = require('./file');
|
||||
|
||||
|
||||
/*
|
||||
An article represent an entry in the Summary.
|
||||
It's defined by a title, a reference, and children articles,
|
||||
@@ -37,8 +36,12 @@ function TOCArticle(def, parent) {
|
||||
var parts = url.parse(this.ref);
|
||||
|
||||
if (!this.isExternal()) {
|
||||
this.path = parts.pathname;
|
||||
this.anchor = parts.hash;
|
||||
var parts = this.ref.split('#');
|
||||
this.path = (parts.length > 1? parts.slice(0, -1).join('#') : this.ref);
|
||||
this.anchor = (parts.length > 1? '#' + _.last(parts) : null);
|
||||
|
||||
// Normalize path to remove ('./', etc)
|
||||
this.path = location.normalize(this.path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,6 +267,17 @@ Summary.prototype.find = function(filter) {
|
||||
return result;
|
||||
};
|
||||
|
||||
// Flatten the list of articles
|
||||
Summary.prototype.flatten = function() {
|
||||
var result = [];
|
||||
|
||||
this.walk(function(article) {
|
||||
result.push(article);
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
// Return the first TOCArticle for a specific page (or path)
|
||||
Summary.prototype.getArticle = function(page) {
|
||||
if (!_.isString(page)) page = page.path;
|
||||
|
||||
+32
-23
@@ -13,6 +13,7 @@ var error = require('./utils/error');
|
||||
var Promise = require('./utils/promise');
|
||||
var Logger = require('./utils/logger');
|
||||
var parsers = require('./parsers');
|
||||
var initBook = require('./init');
|
||||
|
||||
|
||||
/*
|
||||
@@ -92,7 +93,21 @@ function Book(opts) {
|
||||
// List of page in the book
|
||||
this.pages = {};
|
||||
|
||||
// Deprecation for templates
|
||||
Object.defineProperty(this, 'options', {
|
||||
get: function () {
|
||||
this.log.warn.ln('"options" property is deprecated, use config.get(key) instead');
|
||||
var cfg = this.config.dump();
|
||||
error.deprecateField(cfg, 'book', (this.output? this.output.name : null), '"options.generator" property is deprecated, use "output.name" instead');
|
||||
|
||||
return cfg;
|
||||
}
|
||||
});
|
||||
|
||||
_.bindAll(this);
|
||||
|
||||
// Loop for template filters/blocks
|
||||
error.deprecateField(this, 'book', this, '"book" property is deprecated, use "this" directly instead');
|
||||
}
|
||||
|
||||
// Return templating context for the book
|
||||
@@ -108,7 +123,16 @@ Book.prototype.getContext = function() {
|
||||
|
||||
// Parse and prepare the configuration, fail if invalid
|
||||
Book.prototype.prepareConfig = function() {
|
||||
return this.config.load();
|
||||
var that = this;
|
||||
|
||||
return this.config.load()
|
||||
.then(function() {
|
||||
var rootFolder = that.config.get('root');
|
||||
if (!rootFolder) return;
|
||||
|
||||
that.originalRoot = that.root;
|
||||
that.root = path.resolve(that.root, rootFolder);
|
||||
});
|
||||
};
|
||||
|
||||
// Resolve a path in the book source
|
||||
@@ -329,29 +353,14 @@ Book.prototype.isInLanguageBook = function(filename) {
|
||||
});
|
||||
};
|
||||
|
||||
// Locate a book in a folder
|
||||
// - Read the ".gitbook" is exists
|
||||
// - Try the folder itself
|
||||
// - Try a "docs" folder
|
||||
Book.locate = function(fs, root) {
|
||||
return fs.readAsString(path.join(root, '.gitbook'))
|
||||
.then(function(content) {
|
||||
return path.join(root, content);
|
||||
}, function() {
|
||||
// .gitbook doesn't exists, fall back to the root folder
|
||||
return Promise(root);
|
||||
});
|
||||
};
|
||||
// Initialize a book
|
||||
Book.init = function(fs, root, opts) {
|
||||
var book = new Book(_.extend(opts || {}, {
|
||||
root: root,
|
||||
fs: fs
|
||||
}));
|
||||
|
||||
// Locate and setup a book
|
||||
Book.setup = function(fs, root, opts) {
|
||||
return Book.locate(fs, root)
|
||||
.then(function(_root) {
|
||||
return new Book(_.extend(opts || {}, {
|
||||
root: _root,
|
||||
fs: fs
|
||||
}));
|
||||
});
|
||||
return initBook(book);
|
||||
};
|
||||
|
||||
|
||||
|
||||
+5
-4
@@ -42,12 +42,13 @@ var FORMATS = {
|
||||
function bookCmd(fn) {
|
||||
return function(args, kwargs) {
|
||||
var input = path.resolve(args[0] || process.cwd());
|
||||
return Book.setup(nodeFS, input, {
|
||||
var book = new Book({
|
||||
fs: nodeFS,
|
||||
root: input,
|
||||
logLevel: kwargs.log
|
||||
})
|
||||
.then(function(book) {
|
||||
return fn(book, args.slice(1), kwargs);
|
||||
});
|
||||
|
||||
return fn(book, args.slice(1), kwargs);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+31
-18
@@ -7,6 +7,7 @@ var tinylr = require('tiny-lr');
|
||||
var Promise = require('../utils/promise');
|
||||
var PluginsManager = require('../plugins');
|
||||
var Book = require('../book');
|
||||
var initBook = require('../init');
|
||||
|
||||
var helper = require('./helper');
|
||||
var Server = require('./server');
|
||||
@@ -14,6 +15,17 @@ var watch = require('./watch');
|
||||
|
||||
module.exports = {
|
||||
commands: [
|
||||
{
|
||||
name: 'init [book]',
|
||||
description: 'setup and create files for chapters',
|
||||
options: [
|
||||
helper.options.log
|
||||
],
|
||||
exec: function(args) {
|
||||
var input = path.resolve(args[0] || process.cwd());
|
||||
return Book.init(helper.nodeFS, input);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: 'parse [book]',
|
||||
@@ -119,26 +131,27 @@ module.exports = {
|
||||
|
||||
// Generate the book
|
||||
.then(function() {
|
||||
return Book.setup(helper.nodeFS, input, {
|
||||
'logLevel': kwargs.log
|
||||
})
|
||||
.then(function(book) {
|
||||
return book.parse()
|
||||
.then(function() {
|
||||
// Add livereload plugin
|
||||
book.config.set('plugins',
|
||||
book.config.get('plugins')
|
||||
.concat([
|
||||
{ name: 'livereload' }
|
||||
])
|
||||
);
|
||||
var book = new Book({
|
||||
fs: helper.nodeFS,
|
||||
root: input,
|
||||
logLevel: kwargs.log
|
||||
});
|
||||
|
||||
var Out = helper.FORMATS[kwargs.format];
|
||||
var output = new Out(book);
|
||||
return book.parse()
|
||||
.then(function() {
|
||||
// Add livereload plugin
|
||||
book.config.set('plugins',
|
||||
book.config.get('plugins')
|
||||
.concat([
|
||||
{ name: 'livereload' }
|
||||
])
|
||||
);
|
||||
|
||||
return output.generate()
|
||||
.thenResolve(output);
|
||||
});
|
||||
var Out = helper.FORMATS[kwargs.format];
|
||||
var output = new Out(book);
|
||||
|
||||
return output.generate()
|
||||
.thenResolve(output);
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
@@ -4,6 +4,10 @@ module.exports = {
|
||||
'title': 'GitBook Configuration',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'root': {
|
||||
'type': 'string',
|
||||
'title': 'Path fro the root folder containing the book\'s content'
|
||||
},
|
||||
'title': {
|
||||
'type': 'string',
|
||||
'title': 'Title of the book, default is extracted from README'
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
var _ = require('lodash');
|
||||
var path = require('path');
|
||||
|
||||
var fs = require('./utils/fs');
|
||||
var Promise = require('./utils/promise');
|
||||
|
||||
// Initialize folder structure for a book
|
||||
// Read SUMMARY to created the right chapter
|
||||
function initBook(book) {
|
||||
var extensionToUse = '.md';
|
||||
|
||||
book.log.info.ln('init book at', book.root);
|
||||
return fs.mkdirp(book.root)
|
||||
.then(function() {
|
||||
return book.config.load();
|
||||
})
|
||||
.then(function() {
|
||||
book.log.info.ln('detect structure from SUMMARY (if it exists)');
|
||||
return book.summary.load();
|
||||
})
|
||||
.then(function() {
|
||||
var summary = book.summary.path || 'SUMMARY.md';
|
||||
var articles = book.summary.flatten();
|
||||
|
||||
// Use extension of summary
|
||||
extensionToUse = path.extname(summary);
|
||||
|
||||
// Readme doesn't have a path
|
||||
if (!articles[0].path) {
|
||||
articles[0].path = 'README' + extensionToUse;
|
||||
}
|
||||
|
||||
// Summary doesn't exists? create one
|
||||
if (!book.summary.path) {
|
||||
articles.push({
|
||||
title: 'Summary',
|
||||
path: 'SUMMARY'+extensionToUse
|
||||
});
|
||||
}
|
||||
|
||||
// Create files that don't exist
|
||||
return Promise.serie(articles, function(article) {
|
||||
if (!article.path) return;
|
||||
|
||||
var absolutePath = book.resolve(article.path);
|
||||
|
||||
return fs.exists(absolutePath)
|
||||
.then(function(exists) {
|
||||
if(exists) {
|
||||
book.log.info.ln('found', article.path);
|
||||
return;
|
||||
} else {
|
||||
book.log.info.ln('create', article.path);
|
||||
}
|
||||
|
||||
return fs.mkdirp(path.dirname(absolutePath))
|
||||
.then(function() {
|
||||
return fs.writeFile(absolutePath, '# '+article.title+'\n\n');
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(function() {
|
||||
book.log.info.ln('initialization is finished');
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = initBook;
|
||||
@@ -24,6 +24,7 @@ function Output(book, opts, parent) {
|
||||
});
|
||||
|
||||
this.book = book;
|
||||
book.output = this;
|
||||
this.log = this.book.log;
|
||||
|
||||
// Create plugins manager
|
||||
@@ -146,6 +147,7 @@ Output.prototype.prepare = function() {
|
||||
'.ignore',
|
||||
'.bookignore',
|
||||
'node_modules',
|
||||
'_layouts',
|
||||
|
||||
// The configuration file should not be copied in the output
|
||||
this.book.config.path,
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ JSONOutput.prototype.onPage = function(page) {
|
||||
delete json.config;
|
||||
|
||||
// Specify JSON output version
|
||||
json.version = '2';
|
||||
json.version = '3';
|
||||
|
||||
return that.writeFile(
|
||||
page.withExtension('.json'),
|
||||
|
||||
@@ -7,19 +7,7 @@ var error = require('../utils/error');
|
||||
*/
|
||||
function pluginCtx(plugin) {
|
||||
var book = plugin.book;
|
||||
var ctx = {
|
||||
config: book.config,
|
||||
log: plugin.log,
|
||||
|
||||
// Paths
|
||||
resolve: book.resolve
|
||||
};
|
||||
|
||||
// Deprecation
|
||||
error.deprecateField(ctx, 'options', book.config.dump(), '"options" property is deprecated, use config.get(key) instead');
|
||||
|
||||
// Loop for template filters/blocks
|
||||
error.deprecateField(ctx, 'book', ctx, '"book" property is deprecated, use "this" directly instead');
|
||||
var ctx = book;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ function isAnchor(href) {
|
||||
|
||||
// Normalize a path to be a link
|
||||
function normalize(s) {
|
||||
return s.replace(/\\/g, '/');
|
||||
return path.normalize(s).replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
// Convert relative to absolute path
|
||||
@@ -36,7 +36,7 @@ function normalize(s) {
|
||||
function toAbsolute(_href, dir, outdir) {
|
||||
if (isExternal(_href)) return _href;
|
||||
outdir = outdir == undefined? dir : outdir;
|
||||
|
||||
|
||||
_href = normalize(_href);
|
||||
dir = normalize(dir);
|
||||
outdir = normalize(outdir);
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gitbook",
|
||||
"version": "3.0.0-pre.1",
|
||||
"version": "3.0.0-pre.3",
|
||||
"homepage": "https://www.gitbook.com",
|
||||
"description": "Library and cmd utility to generate GitBooks",
|
||||
"main": "lib/index.js",
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
|
||||
// Module API
|
||||
require('./exports');
|
||||
|
||||
// Utilities
|
||||
require('./location');
|
||||
require('./paths');
|
||||
@@ -25,3 +28,6 @@ require('./assets-inliner');
|
||||
require('./output-json');
|
||||
require('./output-website');
|
||||
require('./output-ebook');
|
||||
|
||||
// Misc
|
||||
require('./init');
|
||||
|
||||
+16
-3
@@ -1,18 +1,31 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var _ = require('lodash');
|
||||
var cheerio = require('cheerio');
|
||||
var should = require('should');
|
||||
|
||||
// Assertions to test if an Output has generated a file
|
||||
should.Assertion.add('file', function(file, description) {
|
||||
var rootFolder;
|
||||
if (_.isFunction(this.obj.root)) {
|
||||
rootFolder = this.obj.root();
|
||||
} else {
|
||||
rootFolder = this.obj;
|
||||
}
|
||||
|
||||
this.params = {
|
||||
actual: this.obj.root(),
|
||||
actual: rootFolder,
|
||||
operator: 'have file ' + file,
|
||||
message: description
|
||||
};
|
||||
|
||||
this.obj.should.have.property('resolve').which.is.a.Function;
|
||||
this.assert(fs.existsSync(this.obj.resolve(file)));
|
||||
if (_.isFunction(this.obj.resolve)) {
|
||||
file = this.obj.resolve(file);
|
||||
} else {
|
||||
file = path.resolve(rootFolder, file);
|
||||
}
|
||||
|
||||
this.assert(fs.existsSync(file));
|
||||
});
|
||||
|
||||
should.Assertion.add('html', function(rules, description) {
|
||||
|
||||
+3
-3
@@ -46,7 +46,7 @@ describe('Configuration', function() {
|
||||
return mock.setupDefaultBook()
|
||||
.then(function(_book) {
|
||||
book = _book;
|
||||
return book.config.load();
|
||||
return book.prepareConfig();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -64,7 +64,7 @@ describe('Configuration', function() {
|
||||
})
|
||||
.then(function(_book) {
|
||||
book = _book;
|
||||
return book.config.load();
|
||||
return book.prepareConfig();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -82,7 +82,7 @@ describe('Configuration', function() {
|
||||
})
|
||||
.then(function(_book) {
|
||||
book = _book;
|
||||
return book.config.load();
|
||||
return book.prepareConfig();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
var should = require('should');
|
||||
var gitbook = require('../');
|
||||
|
||||
describe('Exports', function() {
|
||||
it('should export the Book class', function() {
|
||||
should(gitbook.Book).be.a.Function();
|
||||
});
|
||||
|
||||
it('should export the list of commands', function() {
|
||||
should(gitbook.commands).be.an.Array();
|
||||
});
|
||||
});
|
||||
+2
-2
@@ -7,7 +7,7 @@ describe('Glossary', function() {
|
||||
'GLOSSARY.md': ''
|
||||
})
|
||||
.then(function(book) {
|
||||
return book.config.load()
|
||||
return book.prepareConfig()
|
||||
|
||||
.then(function() {
|
||||
return book.glossary.load();
|
||||
@@ -27,7 +27,7 @@ describe('Glossary', function() {
|
||||
})
|
||||
.then(function(_book) {
|
||||
book = _book;
|
||||
return book.config.load();
|
||||
return book.prepareConfig();
|
||||
})
|
||||
.then(function() {
|
||||
return book.glossary.load();
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
var Book = require('../lib/book');
|
||||
var mock = require('./mock');
|
||||
|
||||
describe('Init', function() {
|
||||
|
||||
it('should create file according to summary', function() {
|
||||
return mock.setupFS({
|
||||
'SUMMARY.md': '# Summary\n\n'
|
||||
+ '* [Hello](hello.md)\n'
|
||||
+ '* [Hello 2](hello 2.md)\n'
|
||||
})
|
||||
.then(function(rootFolder) {
|
||||
return Book.init(mock.fs, rootFolder, {
|
||||
log: function() {}
|
||||
})
|
||||
.then(function() {
|
||||
rootFolder.should.have.file('SUMMARY.md');
|
||||
rootFolder.should.have.file('README.md');
|
||||
rootFolder.should.have.file('hello.md');
|
||||
rootFolder.should.have.file('hello 2.md');
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('should create file subfolder', function() {
|
||||
return mock.setupFS({
|
||||
'SUMMARY.md': '# Summary\n\n'
|
||||
+ '* [Hello](test/hello.md)\n'
|
||||
+ '* [Hello 2](test/test2/world.md)\n'
|
||||
})
|
||||
.then(function(rootFolder) {
|
||||
return Book.init(mock.fs, rootFolder, {
|
||||
log: function() {}
|
||||
})
|
||||
.then(function() {
|
||||
rootFolder.should.have.file('README.md');
|
||||
rootFolder.should.have.file('SUMMARY.md');
|
||||
rootFolder.should.have.file('test/hello.md');
|
||||
rootFolder.should.have.file('test/test2/world.md');
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('should create SUMMARY if non-existant', function() {
|
||||
return mock.setupFS({})
|
||||
.then(function(rootFolder) {
|
||||
return Book.init(mock.fs, rootFolder, {
|
||||
log: function() {}
|
||||
})
|
||||
.then(function() {
|
||||
rootFolder.should.have.file('SUMMARY.md');
|
||||
rootFolder.should.have.file('README.md');
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
});
|
||||
+1
-1
@@ -6,7 +6,7 @@ describe('Langs', function() {
|
||||
'LANGS.md': ''
|
||||
})
|
||||
.then(function(book) {
|
||||
return book.config.load()
|
||||
return book.prepareConfig()
|
||||
|
||||
.then(function() {
|
||||
return book.langs.load();
|
||||
|
||||
+17
-10
@@ -1,27 +1,34 @@
|
||||
var path = require('path');
|
||||
var should = require('should');
|
||||
|
||||
var Book = require('../').Book;
|
||||
var mock = require('./mock');
|
||||
|
||||
describe('Locate', function() {
|
||||
it('should use root folder if no .gitbook', function() {
|
||||
return mock.setupFS({
|
||||
return mock.setupBook({
|
||||
'README.md': '# Hello'
|
||||
})
|
||||
.then(function(root) {
|
||||
return Book.locate(mock.fs, root)
|
||||
.should.be.fulfilledWith(root);
|
||||
.then(function(book) {
|
||||
return book.prepareConfig()
|
||||
.then(function() {
|
||||
should(book.originalRoot).not.be.ok();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should use resolve using .gitbook', function() {
|
||||
return mock.setupFS({
|
||||
it('should use resolve using book.js root property', function() {
|
||||
return mock.setupBook({
|
||||
'README.md': '# Hello',
|
||||
'.gitbook': './docs'
|
||||
'docs/README.md': '# Hello Book',
|
||||
'book.json': { root: './docs' }
|
||||
})
|
||||
.then(function(root) {
|
||||
return Book.locate(mock.fs, root)
|
||||
.should.be.fulfilledWith(path.resolve(root, 'docs'));
|
||||
.then(function(book) {
|
||||
return book.prepareConfig()
|
||||
.then(function() {
|
||||
should(book.originalRoot).be.ok();
|
||||
book.root.should.equal(path.resolve(book.originalRoot, 'docs'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+18
-2
@@ -53,7 +53,23 @@ describe('Plugins', function() {
|
||||
}
|
||||
})
|
||||
.then(function(book) {
|
||||
return book.config.load()
|
||||
return book.prepareConfig()
|
||||
.then(function() {
|
||||
var plugins = new PluginsManager(book);
|
||||
return plugins.install();
|
||||
});
|
||||
})
|
||||
.should.be.fulfilledWith(1);
|
||||
});
|
||||
|
||||
it('should correctly install dependencies from GitHub', function() {
|
||||
return mock.setupBook({
|
||||
'book.json': {
|
||||
plugins: ['ga@git+https://github.com/GitbookIO/plugin-ga#master']
|
||||
}
|
||||
})
|
||||
.then(function(book) {
|
||||
return book.prepareConfig()
|
||||
.then(function() {
|
||||
var plugins = new PluginsManager(book);
|
||||
return plugins.install();
|
||||
@@ -90,7 +106,7 @@ describe('Plugins', function() {
|
||||
}
|
||||
})
|
||||
.then(function(book2) {
|
||||
return book2.config.load()
|
||||
return book2.prepareConfig()
|
||||
.then(function() {
|
||||
var plugin = new BookPlugin(book2, 'test-config');
|
||||
return plugin.load(PLUGINS_ROOT);
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ describe('Readme', function() {
|
||||
'README.md': ''
|
||||
})
|
||||
.then(function(book) {
|
||||
return book.config.load()
|
||||
return book.prepareConfig()
|
||||
|
||||
.then(function() {
|
||||
return book.readme.load();
|
||||
|
||||
@@ -59,6 +59,34 @@ describe('Summary / Table of contents', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Unicode summary', function() {
|
||||
var book;
|
||||
|
||||
before(function() {
|
||||
return mockSummary({
|
||||
'SUMMARY.md': '# Summary\n\n'
|
||||
+ '* [Hello](./hello world.md)\n'
|
||||
+ '* [Spanish](./Descripción del problema.md)\n\n'
|
||||
+ '* [Chinese](读了这本书.md)\n\n'
|
||||
})
|
||||
.then(function(_book) {
|
||||
book = _book;
|
||||
});
|
||||
});
|
||||
|
||||
it('should accept article with spaces', function() {
|
||||
should(book.summary.getArticle('hello world.md')).be.ok();
|
||||
});
|
||||
|
||||
it('should accept article with chinese filename', function() {
|
||||
should(book.summary.getArticle('读了这本书.md')).be.ok();
|
||||
});
|
||||
|
||||
it('should accept article with accents', function() {
|
||||
should(book.summary.getArticle('Descripción del problema.md')).be.ok();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Non-empty summary list', function() {
|
||||
var book;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user