mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-10-03 12:10:34 +00:00
Compare commits
71 Commits
3.0.0-pre.13
...
3.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
| d1e226dba5 | |||
| 1923d28d71 | |||
| 484a306adb | |||
| 5bfc9f2f56 | |||
| 86a65e5287 | |||
| 956d301dd7 | |||
| 00d1a7b5a6 | |||
| 2718c9c017 | |||
| 3234c1e03f | |||
| c8f8eece92 | |||
| 7394efa9dc | |||
| 3e4241fc88 | |||
| a5ae79604c | |||
| fc4bdd68a1 | |||
| f83975b022 | |||
| 167d3957bf | |||
| a9571fd67d | |||
| ac87f48ba5 | |||
| 05403f527d | |||
| 53c72f0806 | |||
| c8c2a61f96 | |||
| 08d780d1f6 | |||
| 2e74fafa36 | |||
| 28ac9ab88a | |||
| 26acab4dfb | |||
| d4b562e001 | |||
| 61956e0646 | |||
| 7892259fe6 | |||
| b97d1c7796 | |||
| a091c5b331 | |||
| 784b3379b5 | |||
| 62446e75d2 | |||
| 8aa2f3075c | |||
| 839ee0385a | |||
| d6b60c6116 | |||
| 9013f02850 | |||
| 961d43f085 | |||
| 7bd49606e3 | |||
| d7c8635350 | |||
| 19e9ff81d2 | |||
| e137bf632a | |||
| 2fef898a1e | |||
| 0945807184 | |||
| d85663b153 | |||
| 481a7d790c | |||
| ef589a6b13 | |||
| d5c4af3377 | |||
| 0b4df4cdf2 | |||
| d6814dc48e | |||
| ce50a1d50f | |||
| a76e018d36 | |||
| b06f1fd677 | |||
| 3d8b1880dc | |||
| 1a13c8c9bb | |||
| 852fae3a09 | |||
| d342d31c8e | |||
| 5b3f54fbc8 | |||
| 308ece784c | |||
| 0758ddf04e | |||
| f24d9aef73 | |||
| f8bb55f258 | |||
| 76daebeb84 | |||
| b0d366b7e8 | |||
| 3d0054dd64 | |||
| 13bc89ff44 | |||
| bb910f984e | |||
| e576fdea14 | |||
| c7864927ec | |||
| 54956de59f | |||
| 2cbd30d1f2 | |||
| 55614f1675 |
@@ -13,8 +13,10 @@
|
|||||||
"env": {
|
"env": {
|
||||||
"node": true,
|
"node": true,
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"jest": true,
|
"mocha": true
|
||||||
"jasmine": true
|
},
|
||||||
|
"globals": {
|
||||||
|
"expect": true
|
||||||
},
|
},
|
||||||
"extends": "eslint:recommended"
|
"extends": "eslint:recommended"
|
||||||
}
|
}
|
||||||
+1
-1
@@ -11,7 +11,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- `links.sidebar` configuration is no longer supported, use summary sections instead
|
- `links.sidebar` configuration is no longer supported, use summary sections instead
|
||||||
- `pdf.headerTemplate` and `pdf.footerTemplate` have been replaced by a template in theme/book: `_layout/ebook/pdf_header.html` and `_layout/ebook/pdf_footer.html`
|
- `pdf.headerTemplate` and `pdf.footerTemplate` have been replaced by a template in theme/book: `_layout/ebook/pdf_header.html` and `_layout/ebook/pdf_footer.html`
|
||||||
- Markdown parser is now using CommonMark
|
- Markdown parser is now using CommonMark
|
||||||
- Root folder for the book can be specified in a `.gitbook` file
|
- Root folder for the book can be specified in the `"root"` property of the `book.json` file
|
||||||
- Multi-lingual books share assets folder
|
- Multi-lingual books share assets folder
|
||||||
- YAML front matter is parsed and can extend page's properties
|
- YAML front matter is parsed and can extend page's properties
|
||||||
- Fix `uk` translation
|
- Fix `uk` translation
|
||||||
|
|||||||
@@ -5,13 +5,18 @@ init:
|
|||||||
# Test against these versions of Node.js.
|
# Test against these versions of Node.js.
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
|
- nodejs_version: "6"
|
||||||
- nodejs_version: "5"
|
- nodejs_version: "5"
|
||||||
- nodejs_version: "4"
|
- nodejs_version: "4"
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
|
||||||
# Install scripts. (runs after repo cloning)
|
# Install scripts. (runs after repo cloning)
|
||||||
install:
|
install:
|
||||||
# Get the latest stable version of Node.js or io.js
|
# Get the latest stable version of Node.js or io.js
|
||||||
- ps: Install-Product node $env:nodejs_version
|
- ps: Install-Product node $env:nodejs_version
|
||||||
|
- set CI=true
|
||||||
# install svgexport
|
# install svgexport
|
||||||
- npm install svgexport -g
|
- npm install svgexport -g
|
||||||
# install modules
|
# install modules
|
||||||
@@ -27,3 +32,7 @@ test_script:
|
|||||||
|
|
||||||
# Don't actually build.
|
# Don't actually build.
|
||||||
build: off
|
build: off
|
||||||
|
|
||||||
|
# Clone only last commit
|
||||||
|
shallow_clone: true
|
||||||
|
clone_depth: 1
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ GitBook allows you to customize your book using a flexible configuration. These
|
|||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
| -------- | ----------- |
|
| -------- | ----------- |
|
||||||
| `root` | Path to the root folder containing all the book's files, except `book.json`|
|
| `root` | Path to the root folder containing all the book's files, except `book.json`|
|
||||||
|
| `structure` | To specify paths for Readme, Summary, Glossary etc. See [Structure paragraph](#structure). |
|
||||||
| `title` | Title of your book, default value is extracted from the README. On GitBook.com this field is pre-filled. |
|
| `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. |
|
| `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. |
|
| `author` | Name of the author. On GitBook.com this field is pre-filled. |
|
||||||
@@ -32,6 +33,18 @@ Since version 3.0.0, GitBook can use themes. See [the theming section](themes/RE
|
|||||||
| -------- | ----------- |
|
| -------- | ----------- |
|
||||||
| `theme` | The theme to use for the book |
|
| `theme` | The theme to use for the book |
|
||||||
|
|
||||||
|
### Structure
|
||||||
|
|
||||||
|
In addition to the `root` variable, you can tell Gitbook the name of the files for Readme, Summary, Glossary, Languages (instead of using the default names such as `README.md`).
|
||||||
|
These files must be at the root of your book (or the root of every language book). Paths such as `dir/MY_README.md` are not accepted.
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `structure.readme` | Readme file name (defaults to `README.md`) |
|
||||||
|
| `structure.summary` | Summary file name (defaults to `SUMMARY.md`) |
|
||||||
|
| `structure.glossary` | Glossary file name (defaults to `GLOSSARY.md`) |
|
||||||
|
| `structure.languages` | Languages file name (defaults to `LANGS.md`) |
|
||||||
|
|
||||||
### PDF Options
|
### PDF Options
|
||||||
|
|
||||||
PDF Output can be customized using a set of options in the `book.json`:
|
PDF Output can be customized using a set of options in the `book.json`:
|
||||||
|
|||||||
+3
-3
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
Allows you to specify terms and their respective definitions to be displayed as annotations. Based on those terms, GitBook will automatically build an index and highlight those terms in pages.
|
Allows you to specify terms and their respective definitions to be displayed as annotations. Based on those terms, GitBook will automatically build an index and highlight those terms in pages.
|
||||||
|
|
||||||
The `GLOSSARY.md` format is very simple :
|
The `GLOSSARY.md` format is a list of `h2` headings, along with a description paragraph:
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
# Term
|
## Term
|
||||||
Definition for this term
|
Definition for this term
|
||||||
|
|
||||||
# Another term
|
## Another term
|
||||||
With it's definition, this can contain bold text
|
With it's definition, this can contain bold text
|
||||||
and all other kinds of inline markup ...
|
and all other kinds of inline markup ...
|
||||||
```
|
```
|
||||||
|
|||||||
+1
-1
@@ -37,7 +37,7 @@ var filepath = output.resolve('myimage.png');
|
|||||||
var fileurl = output.toURL('mychapter/README.md');
|
var fileurl = output.toURL('mychapter/README.md');
|
||||||
|
|
||||||
// Write a file in the output folder
|
// Write a file in the output folder
|
||||||
output.write('hello.txt', 'Hello World')
|
output.writeFile('hello.txt', 'Hello World')
|
||||||
.then(function() { ... });
|
.then(function() { ... });
|
||||||
|
|
||||||
// Copy a file to the output folder
|
// Copy a file to the output folder
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ It integrates well with the [GitBook Editor](https://www.gitbook.com/editor).
|
|||||||
|
|
||||||
Installing GitBook is easy and straightforward. Your system just needs to meet these two requirements:
|
Installing GitBook is easy and straightforward. Your system just needs to meet these two requirements:
|
||||||
|
|
||||||
* NodeJS (v4.0.0 and above are adviced)
|
* NodeJS (v4.0.0 and above is recommended)
|
||||||
* Windows, Linux, Unix, or Mac OS X
|
* Windows, Linux, Unix, or Mac OS X
|
||||||
|
|
||||||
##### Install with NPM
|
##### Install with NPM
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
var path = require('path');
|
|
||||||
var fs = require('fs');
|
|
||||||
|
|
||||||
var matchers = {
|
|
||||||
/**
|
|
||||||
Verify that a file exists in a directory
|
|
||||||
*/
|
|
||||||
toHaveFile: function () {
|
|
||||||
return {
|
|
||||||
compare: function (actual, expected) {
|
|
||||||
var filePath = path.join(actual, expected);
|
|
||||||
var exists = fs.existsSync(filePath);
|
|
||||||
|
|
||||||
return {
|
|
||||||
pass: exists
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
jasmine.getEnv().beforeEach(function () {
|
|
||||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000;
|
|
||||||
jasmine.addMatchers(matchers);
|
|
||||||
});
|
|
||||||
@@ -3,7 +3,7 @@ var initBook = require('../init');
|
|||||||
|
|
||||||
describe('initBook', function() {
|
describe('initBook', function() {
|
||||||
|
|
||||||
pit('should create a README and SUMMARY for empty book', function() {
|
it('should create a README and SUMMARY for empty book', function() {
|
||||||
var dir = tmp.dirSync();
|
var dir = tmp.dirSync();
|
||||||
|
|
||||||
return initBook(dir.name)
|
return initBook(dir.name)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
var Config = require('../models/config');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Decode changes from a JS API to a config object
|
Decode changes from a JS API to a config object
|
||||||
|
|
||||||
@@ -13,7 +11,7 @@ function decodeGlobal(config, result) {
|
|||||||
delete values.generator;
|
delete values.generator;
|
||||||
delete values.output;
|
delete values.output;
|
||||||
|
|
||||||
return Config.updateValues(config, values);
|
return config.updateValues(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = decodeGlobal;
|
module.exports = decodeGlobal;
|
||||||
|
|||||||
+84
-2
@@ -5,11 +5,15 @@ var fs = require('../utils/fs');
|
|||||||
|
|
||||||
var Plugins = require('../plugins');
|
var Plugins = require('../plugins');
|
||||||
var deprecate = require('./deprecate');
|
var deprecate = require('./deprecate');
|
||||||
var encodeConfig = require('./encodeConfig');
|
|
||||||
var encodeNavigation = require('./encodeNavigation');
|
|
||||||
var fileToURL = require('../output/helper/fileToURL');
|
var fileToURL = require('../output/helper/fileToURL');
|
||||||
var defaultBlocks = require('../constants/defaultBlocks');
|
var defaultBlocks = require('../constants/defaultBlocks');
|
||||||
var gitbook = require('../gitbook');
|
var gitbook = require('../gitbook');
|
||||||
|
var parsers = require('../parsers');
|
||||||
|
|
||||||
|
var encodeConfig = require('./encodeConfig');
|
||||||
|
var encodeSummary = require('./encodeSummary');
|
||||||
|
var encodeNavigation = require('./encodeNavigation');
|
||||||
|
var encodePage = require('./encodePage');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Encode a global context into a JS object
|
Encode a global context into a JS object
|
||||||
@@ -29,6 +33,7 @@ function encodeGlobal(output) {
|
|||||||
var result = {
|
var result = {
|
||||||
log: logger,
|
log: logger,
|
||||||
config: encodeConfig(output, book.getConfig()),
|
config: encodeConfig(output, book.getConfig()),
|
||||||
|
summary: encodeSummary(output, book.getSummary()),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Check if the book is a multilingual book
|
Check if the book is a multilingual book
|
||||||
@@ -78,6 +83,47 @@ function encodeGlobal(output) {
|
|||||||
return path.resolve(book.getContentRoot(), fileName);
|
return path.resolve(book.getContentRoot(), fileName);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
Resolve a page by it path
|
||||||
|
|
||||||
|
@param {String} filePath
|
||||||
|
@return {String}
|
||||||
|
*/
|
||||||
|
getPageByPath: function(filePath) {
|
||||||
|
var page = output.getPage(filePath);
|
||||||
|
if (!page) return undefined;
|
||||||
|
|
||||||
|
return encodePage(output, page);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
Render a block of text (markdown/asciidoc)
|
||||||
|
|
||||||
|
@param {String} type
|
||||||
|
@param {String} text
|
||||||
|
@return {Promise<String>}
|
||||||
|
*/
|
||||||
|
renderBlock: function(type, text) {
|
||||||
|
var parser = parsers.get(type);
|
||||||
|
|
||||||
|
return parser.parsePage(text)
|
||||||
|
.get('content');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
Render an inline text (markdown/asciidoc)
|
||||||
|
|
||||||
|
@param {String} type
|
||||||
|
@param {String} text
|
||||||
|
@return {Promise<String>}
|
||||||
|
*/
|
||||||
|
renderInline: function(type, text) {
|
||||||
|
var parser = parsers.get(type);
|
||||||
|
|
||||||
|
return parser.parseInline(text)
|
||||||
|
.get('content');
|
||||||
|
},
|
||||||
|
|
||||||
template: {
|
template: {
|
||||||
/**
|
/**
|
||||||
Apply a templating block and returns its result
|
Apply a templating block and returns its result
|
||||||
@@ -125,6 +171,21 @@ function encodeGlobal(output) {
|
|||||||
return fileToURL(output, filePath);
|
return fileToURL(output, filePath);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
Check that a file exists.
|
||||||
|
|
||||||
|
@param {String} fileName
|
||||||
|
@return {Promise}
|
||||||
|
*/
|
||||||
|
hasFile: function(fileName, content) {
|
||||||
|
return Promise()
|
||||||
|
.then(function() {
|
||||||
|
var filePath = PathUtils.resolveInRoot(outputFolder, fileName);
|
||||||
|
|
||||||
|
return fs.exists(filePath);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Write a file to the output folder,
|
Write a file to the output folder,
|
||||||
It creates the required folder
|
It creates the required folder
|
||||||
@@ -143,6 +204,27 @@ function encodeGlobal(output) {
|
|||||||
return fs.writeFile(filePath, content);
|
return fs.writeFile(filePath, content);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
Copy a file to the output folder
|
||||||
|
It creates the required folder.
|
||||||
|
|
||||||
|
@param {String} inputFile
|
||||||
|
@param {String} outputFile
|
||||||
|
@param {Buffer} content
|
||||||
|
@return {Promise}
|
||||||
|
*/
|
||||||
|
copyFile: function(inputFile, outputFile, content) {
|
||||||
|
return Promise()
|
||||||
|
.then(function() {
|
||||||
|
var outputFilePath = PathUtils.resolveInRoot(outputFolder, outputFile);
|
||||||
|
|
||||||
|
return fs.ensureFile(outputFilePath)
|
||||||
|
.then(function() {
|
||||||
|
return fs.copy(inputFile, outputFilePath);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
var encodeSummaryArticle = require('../json/encodeSummaryArticle');
|
||||||
|
|
||||||
|
/**
|
||||||
|
Encode summary to provide an API to plugin
|
||||||
|
|
||||||
|
@param {Output} output
|
||||||
|
@param {Config} config
|
||||||
|
@return {Object}
|
||||||
|
*/
|
||||||
|
function encodeSummary(output, summary) {
|
||||||
|
var result = {
|
||||||
|
/**
|
||||||
|
Iterate over the summary, it stops when the "iter" returns false
|
||||||
|
|
||||||
|
@param {Function} iter
|
||||||
|
*/
|
||||||
|
walk: function (iter) {
|
||||||
|
summary.getArticle(function(article) {
|
||||||
|
var jsonArticle = encodeSummaryArticle(article, false);
|
||||||
|
|
||||||
|
return iter(jsonArticle);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get an article by its level
|
||||||
|
|
||||||
|
@param {String} level
|
||||||
|
@return {Object}
|
||||||
|
*/
|
||||||
|
getArticleByLevel: function(level) {
|
||||||
|
var article = summary.getByLevel(level);
|
||||||
|
return (article? encodeSummaryArticle(article) : undefined);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get an article by its path
|
||||||
|
|
||||||
|
@param {String} level
|
||||||
|
@return {Object}
|
||||||
|
*/
|
||||||
|
getArticleByPath: function(level) {
|
||||||
|
var article = summary.getByPath(level);
|
||||||
|
return (article? encodeSummaryArticle(article) : undefined);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = encodeSummary;
|
||||||
+5
-1
@@ -11,5 +11,9 @@ module.exports = {
|
|||||||
|
|
||||||
// Modifiers
|
// Modifiers
|
||||||
SummaryModifier: Modifiers.Summary,
|
SummaryModifier: Modifiers.Summary,
|
||||||
ConfigModifier: Modifiers.Config
|
ConfigModifier: Modifiers.Config,
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
CONFIG_FILES: require('./constants/configFiles.js'),
|
||||||
|
IGNORE_FILES: require('./constants/ignoreFiles.js')
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,8 +18,10 @@ module.exports = function(format) {
|
|||||||
options.log
|
options.log
|
||||||
],
|
],
|
||||||
exec: function(args, kwargs) {
|
exec: function(args, kwargs) {
|
||||||
|
var extension = '.' + format;
|
||||||
|
|
||||||
// Output file will be stored in
|
// Output file will be stored in
|
||||||
var outputFile = args[1] || ('book.' + format);
|
var outputFile = args[1] || ('book' + extension);
|
||||||
|
|
||||||
// Create temporary directory
|
// Create temporary directory
|
||||||
var outputFolder = tmp.dirSync().name;
|
var outputFolder = tmp.dirSync().name;
|
||||||
@@ -42,23 +44,23 @@ module.exports = function(format) {
|
|||||||
var languages = book.getLanguages();
|
var languages = book.getLanguages();
|
||||||
|
|
||||||
if (book.isMultilingual()) {
|
if (book.isMultilingual()) {
|
||||||
return Promise.ForEach(languages, function(lang) {
|
return Promise.forEach(languages.getList(), function(lang) {
|
||||||
var langID = lang.getID();
|
var langID = lang.getID();
|
||||||
|
|
||||||
var langOutputFile = path.join(
|
var langOutputFile = path.join(
|
||||||
path.dirname(outputFile),
|
path.dirname(outputFile),
|
||||||
path.basename(outputFile, format) + '_' + langID + '.' + format
|
path.basename(outputFile, extension) + '_' + langID + extension
|
||||||
);
|
);
|
||||||
|
|
||||||
return fs.copy(
|
return fs.copy(
|
||||||
path.resolve(outputFolder, langID, 'index.' + format),
|
path.resolve(outputFolder, langID, 'index' + extension),
|
||||||
langOutputFile
|
langOutputFile
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.thenResolve(languages.getCount());
|
.thenResolve(languages.getCount());
|
||||||
} else {
|
} else {
|
||||||
return fs.copy(
|
return fs.copy(
|
||||||
path.resolve(outputFolder, 'index.' + format),
|
path.resolve(outputFolder, 'index' + extension),
|
||||||
outputFile
|
outputFile
|
||||||
).thenResolve(1);
|
).thenResolve(1);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ var options = require('./options');
|
|||||||
var initBook = require('../init');
|
var initBook = require('../init');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'install [book]',
|
name: 'init [book]',
|
||||||
description: 'setup and create files for chapters',
|
description: 'setup and create files for chapters',
|
||||||
options: [
|
options: [
|
||||||
options.log
|
options.log
|
||||||
|
|||||||
+45
-10
@@ -16,12 +16,26 @@ var watch = require('./watch');
|
|||||||
|
|
||||||
var server, lrServer, lrPath;
|
var server, lrServer, lrPath;
|
||||||
|
|
||||||
|
function waitForCtrlC() {
|
||||||
|
var d = Promise.defer();
|
||||||
|
|
||||||
|
process.on('SIGINT', function() {
|
||||||
|
d.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
return d.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function generateBook(args, kwargs) {
|
function generateBook(args, kwargs) {
|
||||||
var port = kwargs.port;
|
var port = kwargs.port;
|
||||||
var outputFolder = getOutputFolder(args);
|
var outputFolder = getOutputFolder(args);
|
||||||
var book = getBook(args, kwargs);
|
var book = getBook(args, kwargs);
|
||||||
var Generator = Output.getGenerator(kwargs.format);
|
var Generator = Output.getGenerator(kwargs.format);
|
||||||
|
|
||||||
|
var hasWatch = kwargs['watch'];
|
||||||
|
var hasLiveReloading = kwargs['live'];
|
||||||
|
|
||||||
// Stop server if running
|
// Stop server if running
|
||||||
if (server.isRunning()) console.log('Stopping server');
|
if (server.isRunning()) console.log('Stopping server');
|
||||||
|
|
||||||
@@ -29,8 +43,10 @@ function generateBook(args, kwargs) {
|
|||||||
.then(function() {
|
.then(function() {
|
||||||
return Parse.parseBook(book)
|
return Parse.parseBook(book)
|
||||||
.then(function(resultBook) {
|
.then(function(resultBook) {
|
||||||
// Enable livereload plugin
|
if (hasLiveReloading) {
|
||||||
resultBook = ConfigModifier.addPlugin(resultBook, 'livereload');
|
// Enable livereload plugin
|
||||||
|
resultBook = ConfigModifier.addPlugin(resultBook, 'livereload');
|
||||||
|
}
|
||||||
|
|
||||||
return Output.generate(Generator, resultBook, {
|
return Output.generate(Generator, resultBook, {
|
||||||
root: outputFolder
|
root: outputFolder
|
||||||
@@ -45,7 +61,7 @@ function generateBook(args, kwargs) {
|
|||||||
.then(function() {
|
.then(function() {
|
||||||
console.log('Serving book on http://localhost:'+port);
|
console.log('Serving book on http://localhost:'+port);
|
||||||
|
|
||||||
if (lrPath) {
|
if (lrPath && hasLiveReloading) {
|
||||||
// trigger livereload
|
// trigger livereload
|
||||||
lrServer.changed({
|
lrServer.changed({
|
||||||
body: {
|
body: {
|
||||||
@@ -55,7 +71,9 @@ function generateBook(args, kwargs) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(function() {
|
.then(function() {
|
||||||
if (!kwargs.watch) return;
|
if (!hasWatch) {
|
||||||
|
return waitForCtrlC();
|
||||||
|
}
|
||||||
|
|
||||||
return watch(book.getRoot())
|
return watch(book.getRoot())
|
||||||
.then(function(filepath) {
|
.then(function(filepath) {
|
||||||
@@ -84,7 +102,12 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'watch',
|
name: 'watch',
|
||||||
description: 'Enable/disable file watcher',
|
description: 'Enable file watcher and live reloading',
|
||||||
|
defaults: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'live',
|
||||||
|
description: 'Enable live reloading',
|
||||||
defaults: true
|
defaults: true
|
||||||
},
|
},
|
||||||
options.log,
|
options.log,
|
||||||
@@ -92,13 +115,25 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
exec: function(args, kwargs) {
|
exec: function(args, kwargs) {
|
||||||
server = new Server();
|
server = new Server();
|
||||||
lrServer = tinylr({});
|
var hasWatch = kwargs['watch'];
|
||||||
|
var hasLiveReloading = kwargs['live'];
|
||||||
|
|
||||||
return Promise.nfcall(lrServer.listen.bind(lrServer), kwargs.lrport)
|
return Promise()
|
||||||
|
.then(function() {
|
||||||
|
if (!hasWatch || !hasLiveReloading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lrServer = tinylr({});
|
||||||
|
return Promise.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('');
|
||||||
|
|
||||||
|
});
|
||||||
|
})
|
||||||
.then(function() {
|
.then(function() {
|
||||||
console.log('Live reload server started on port:', kwargs.lrport);
|
|
||||||
console.log('Press CTRL+C to quit ...');
|
|
||||||
console.log('');
|
|
||||||
return generateBook(args, kwargs);
|
return generateBook(args, kwargs);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
jest.autoMockOff();
|
var createMockFS = require('../mock');
|
||||||
|
|
||||||
describe('MockFS', function() {
|
describe('MockFS', function() {
|
||||||
var createMockFS = require('../mock');
|
|
||||||
var fs = createMockFS({
|
var fs = createMockFS({
|
||||||
'README.md': 'Hello World',
|
'README.md': 'Hello World',
|
||||||
'SUMMARY.md': '# Summary',
|
'SUMMARY.md': '# Summary',
|
||||||
@@ -15,35 +14,35 @@ describe('MockFS', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('exists', function() {
|
describe('exists', function() {
|
||||||
pit('must return true for a file', function() {
|
it('must return true for a file', function() {
|
||||||
return fs.exists('README.md')
|
return fs.exists('README.md')
|
||||||
.then(function(result) {
|
.then(function(result) {
|
||||||
expect(result).toBeTruthy();
|
expect(result).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('must return false for a non existing file', function() {
|
it('must return false for a non existing file', function() {
|
||||||
return fs.exists('README_NOTEXISTS.md')
|
return fs.exists('README_NOTEXISTS.md')
|
||||||
.then(function(result) {
|
.then(function(result) {
|
||||||
expect(result).toBeFalsy();
|
expect(result).toBeFalsy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('must return true for a directory', function() {
|
it('must return true for a directory', function() {
|
||||||
return fs.exists('folder')
|
return fs.exists('folder')
|
||||||
.then(function(result) {
|
.then(function(result) {
|
||||||
expect(result).toBeTruthy();
|
expect(result).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('must return true for a deep file', function() {
|
it('must return true for a deep file', function() {
|
||||||
return fs.exists('folder/test.md')
|
return fs.exists('folder/test.md')
|
||||||
.then(function(result) {
|
.then(function(result) {
|
||||||
expect(result).toBeTruthy();
|
expect(result).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('must return true for a deep file (2)', function() {
|
it('must return true for a deep file (2)', function() {
|
||||||
return fs.exists('folder/folder2/hello.md')
|
return fs.exists('folder/folder2/hello.md')
|
||||||
.then(function(result) {
|
.then(function(result) {
|
||||||
expect(result).toBeTruthy();
|
expect(result).toBeTruthy();
|
||||||
@@ -52,14 +51,14 @@ describe('MockFS', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('readAsString', function() {
|
describe('readAsString', function() {
|
||||||
pit('must return content for a file', function() {
|
it('must return content for a file', function() {
|
||||||
return fs.readAsString('README.md')
|
return fs.readAsString('README.md')
|
||||||
.then(function(result) {
|
.then(function(result) {
|
||||||
expect(result).toBe('Hello World');
|
expect(result).toBe('Hello World');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('must return content for a deep file', function() {
|
it('must return content for a deep file', function() {
|
||||||
return fs.readAsString('folder/test.md')
|
return fs.readAsString('folder/test.md')
|
||||||
.then(function(result) {
|
.then(function(result) {
|
||||||
expect(result).toBe('Cool');
|
expect(result).toBe('Cool');
|
||||||
@@ -68,7 +67,7 @@ describe('MockFS', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('readDir', function() {
|
describe('readDir', function() {
|
||||||
pit('must return content for a directory', function() {
|
it('must return content for a directory', function() {
|
||||||
return fs.readDir('./')
|
return fs.readDir('./')
|
||||||
.then(function(files) {
|
.then(function(files) {
|
||||||
expect(files.size).toBe(3);
|
expect(files.size).toBe(3);
|
||||||
|
|||||||
+5
-2
@@ -47,8 +47,11 @@ function initBook(rootFolder) {
|
|||||||
|
|
||||||
// Write pages
|
// Write pages
|
||||||
return Promise.forEach(articles, function(article) {
|
return Promise.forEach(articles, function(article) {
|
||||||
var filePath = path.join(rootFolder, article.getPath());
|
var articlePath = article.getPath();
|
||||||
if (!filePath) return;
|
var filePath = articlePath? path.join(rootFolder, articlePath) : null;
|
||||||
|
if (!filePath) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return fs.assertFile(filePath, function() {
|
return fs.assertFile(filePath, function() {
|
||||||
return fs.ensureFile(filePath)
|
return fs.ensureFile(filePath)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ var gitbook = require('../gitbook');
|
|||||||
var encodeSummary = require('./encodeSummary');
|
var encodeSummary = require('./encodeSummary');
|
||||||
var encodeGlossary = require('./encodeGlossary');
|
var encodeGlossary = require('./encodeGlossary');
|
||||||
var encodeReadme = require('./encodeReadme');
|
var encodeReadme = require('./encodeReadme');
|
||||||
|
var encodeLanguages = require('./encodeLanguages');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Encode a book to JSON
|
Encode a book to JSON
|
||||||
@@ -22,6 +23,9 @@ function encodeBookToJson(book) {
|
|||||||
glossary: encodeGlossary(book.getGlossary()),
|
glossary: encodeGlossary(book.getGlossary()),
|
||||||
readme: encodeReadme(book.getReadme()),
|
readme: encodeReadme(book.getReadme()),
|
||||||
config: book.getConfig().getValues().toJS(),
|
config: book.getConfig().getValues().toJS(),
|
||||||
|
|
||||||
|
languages: book.isMultilingual()? encodeLanguages(book.getLanguages()) : undefined,
|
||||||
|
|
||||||
gitbook: {
|
gitbook: {
|
||||||
version: gitbook.version,
|
version: gitbook.version,
|
||||||
time: gitbook.START_TIME
|
time: gitbook.START_TIME
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
var encodeFile = require('./encodeFile');
|
||||||
|
|
||||||
|
/**
|
||||||
|
Encode a languages listing to JSON
|
||||||
|
|
||||||
|
@param {Languages}
|
||||||
|
@return {Object}
|
||||||
|
*/
|
||||||
|
function encodeLanguages(languages) {
|
||||||
|
var file = languages.getFile();
|
||||||
|
var list = languages.getList();
|
||||||
|
|
||||||
|
return {
|
||||||
|
file: encodeFile(file),
|
||||||
|
list: list
|
||||||
|
.valueSeq()
|
||||||
|
.map(function(lang) {
|
||||||
|
return {
|
||||||
|
id: lang.getID(),
|
||||||
|
title: lang.getTitle()
|
||||||
|
};
|
||||||
|
}).toJS()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = encodeLanguages;
|
||||||
@@ -20,6 +20,7 @@ function encodeSummaryArticle(article, recursive) {
|
|||||||
anchor: article.getAnchor(),
|
anchor: article.getAnchor(),
|
||||||
url: article.getUrl(),
|
url: article.getUrl(),
|
||||||
path: article.getPath(),
|
path: article.getPath(),
|
||||||
|
ref: article.getRef(),
|
||||||
articles: articles
|
articles: articles
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -7,5 +7,6 @@ module.exports = {
|
|||||||
encodePage: require('./encodePage'),
|
encodePage: require('./encodePage'),
|
||||||
encodeSummary: require('./encodeSummary'),
|
encodeSummary: require('./encodeSummary'),
|
||||||
encodeSummaryArticle: require('./encodeSummaryArticle'),
|
encodeSummaryArticle: require('./encodeSummaryArticle'),
|
||||||
encodeReadme: require('./encodeReadme')
|
encodeReadme: require('./encodeReadme'),
|
||||||
|
encodeLanguages: require('./encodeLanguages')
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
jest.autoMockOff();
|
|
||||||
|
|
||||||
var Immutable = require('immutable');
|
var Immutable = require('immutable');
|
||||||
|
var Config = require('../config');
|
||||||
|
|
||||||
describe('Config', function() {
|
describe('Config', function() {
|
||||||
var Config = require('../config');
|
|
||||||
|
|
||||||
var config = Config.createWithValues({
|
var config = Config.createWithValues({
|
||||||
hello: {
|
hello: {
|
||||||
world: 1,
|
world: 1,
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
jest.autoMockOff();
|
var File = require('../file');
|
||||||
|
var Glossary = require('../glossary');
|
||||||
|
var GlossaryEntry = require('../glossaryEntry');
|
||||||
|
|
||||||
describe('Glossary', function() {
|
describe('Glossary', function() {
|
||||||
var File = require('../file');
|
|
||||||
var Glossary = require('../glossary');
|
|
||||||
var GlossaryEntry = require('../glossaryEntry');
|
|
||||||
|
|
||||||
var glossary = Glossary.createFromEntries(File(), [
|
var glossary = Glossary.createFromEntries(File(), [
|
||||||
{
|
{
|
||||||
name: 'Hello World',
|
name: 'Hello World',
|
||||||
@@ -30,7 +28,7 @@ describe('Glossary', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('toText', function() {
|
describe('toText', function() {
|
||||||
pit('return as markdown', function() {
|
it('return as markdown', function() {
|
||||||
return glossary.toText('.md')
|
return glossary.toText('.md')
|
||||||
.then(function(text) {
|
.then(function(text) {
|
||||||
expect(text).toContain('# Glossary');
|
expect(text).toContain('# Glossary');
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
jest.autoMockOff();
|
var GlossaryEntry = require('../glossaryEntry');
|
||||||
|
|
||||||
describe('GlossaryEntry', function() {
|
describe('GlossaryEntry', function() {
|
||||||
var GlossaryEntry = require('../glossaryEntry');
|
|
||||||
|
|
||||||
describe('getID', function() {
|
describe('getID', function() {
|
||||||
it('must return a normalized ID', function() {
|
it('must return a normalized ID', function() {
|
||||||
var entry = new GlossaryEntry({
|
var entry = new GlossaryEntry({
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
describe('PluginDependency', function() {
|
var Immutable = require('immutable');
|
||||||
var PluginDependency = require('../pluginDependency');
|
var PluginDependency = require('../pluginDependency');
|
||||||
|
|
||||||
|
describe('PluginDependency', function() {
|
||||||
describe('createFromString', function() {
|
describe('createFromString', function() {
|
||||||
it('must parse name', function() {
|
it('must parse name', function() {
|
||||||
var plugin = PluginDependency.createFromString('hello');
|
var plugin = PluginDependency.createFromString('hello');
|
||||||
@@ -42,6 +43,20 @@ describe('PluginDependency', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('listToArray', function() {
|
||||||
|
var list = PluginDependency.listToArray(Immutable.List([
|
||||||
|
PluginDependency.createFromString('hello@1.0.0'),
|
||||||
|
PluginDependency.createFromString('noversion'),
|
||||||
|
PluginDependency.createFromString('-disabled')
|
||||||
|
]));
|
||||||
|
|
||||||
|
expect(list).toEqual([
|
||||||
|
'hello@1.0.0',
|
||||||
|
'noversion',
|
||||||
|
'-disabled'
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,11 +8,18 @@ describe('Summary', function() {
|
|||||||
articles: [
|
articles: [
|
||||||
{
|
{
|
||||||
title: 'My First Article',
|
title: 'My First Article',
|
||||||
path: 'README.md'
|
ref: 'README.md'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'My Second Article',
|
title: 'My Second Article',
|
||||||
path: 'article.md'
|
ref: 'article.md'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Article without ref'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Article with absolute ref',
|
||||||
|
ref: 'https://google.fr'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -33,7 +40,7 @@ describe('Summary', function() {
|
|||||||
var part = summary.getByLevel('1');
|
var part = summary.getByLevel('1');
|
||||||
|
|
||||||
expect(part).toBeDefined();
|
expect(part).toBeDefined();
|
||||||
expect(part.getArticles().size).toBe(2);
|
expect(part.getArticles().size).toBe(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can return a Part (2)', function() {
|
it('can return a Part (2)', function() {
|
||||||
@@ -66,10 +73,16 @@ describe('Summary', function() {
|
|||||||
expect(article).toBeDefined();
|
expect(article).toBeDefined();
|
||||||
expect(article.getTitle()).toBe('My Second Article');
|
expect(article.getTitle()).toBe('My Second Article');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('return undefined if not found', function() {
|
||||||
|
var article = summary.getByPath('NOT_EXISTING.md');
|
||||||
|
|
||||||
|
expect(article).toBeFalsy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toText', function() {
|
describe('toText', function() {
|
||||||
pit('return as markdown', function() {
|
it('return as markdown', function() {
|
||||||
return summary.toText('.md')
|
return summary.toText('.md')
|
||||||
.then(function(text) {
|
.then(function(text) {
|
||||||
expect(text).toContain('# Summary');
|
expect(text).toContain('# Summary');
|
||||||
|
|||||||
@@ -6,14 +6,16 @@ describe('TemplateBlock', function() {
|
|||||||
var TemplateBlock = require('../templateBlock');
|
var TemplateBlock = require('../templateBlock');
|
||||||
|
|
||||||
describe('create', function() {
|
describe('create', function() {
|
||||||
pit('must initialize a simple TemplateBlock from a function', function() {
|
it('must initialize a simple TemplateBlock from a function', function() {
|
||||||
var templateBlock = TemplateBlock.create('sayhello', function(block) {
|
var templateBlock = TemplateBlock.create('sayhello', function(block) {
|
||||||
return '<p>Hello, World!</p>';
|
return {
|
||||||
|
body: '<p>Hello, World!</p>',
|
||||||
|
parse: true
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check basic templateBlock properties
|
// Check basic templateBlock properties
|
||||||
expect(templateBlock.getName()).toBe('sayhello');
|
expect(templateBlock.getName()).toBe('sayhello');
|
||||||
expect(templateBlock.getParse()).toBeTruthy();
|
|
||||||
expect(templateBlock.getEndTag()).toBe('endsayhello');
|
expect(templateBlock.getEndTag()).toBe('endsayhello');
|
||||||
expect(templateBlock.getBlocks().size).toBe(0);
|
expect(templateBlock.getBlocks().size).toBe(0);
|
||||||
expect(templateBlock.getExtensionName()).toBe('BlocksayhelloExtension');
|
expect(templateBlock.getExtensionName()).toBe('BlocksayhelloExtension');
|
||||||
@@ -33,10 +35,13 @@ describe('TemplateBlock', function() {
|
|||||||
describe('getShortcuts', function() {
|
describe('getShortcuts', function() {
|
||||||
it('must return undefined if no shortcuts', function() {
|
it('must return undefined if no shortcuts', function() {
|
||||||
var templateBlock = TemplateBlock.create('sayhello', function(block) {
|
var templateBlock = TemplateBlock.create('sayhello', function(block) {
|
||||||
return '<p>Hello, World!</p>';
|
return {
|
||||||
|
body: '<p>Hello, World!</p>',
|
||||||
|
parse: true
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(templateBlock.getShortcuts()).not.toBeDefined();
|
expect(templateBlock.getShortcuts()).toNotExist();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('must return complete shortcut', function() {
|
it('must return complete shortcut', function() {
|
||||||
@@ -62,9 +67,42 @@ describe('TemplateBlock', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('toNunjucksExt()', function() {
|
describe('toNunjucksExt()', function() {
|
||||||
pit('must create a valid nunjucks extension', function() {
|
it('should replace by block anchor', function() {
|
||||||
var templateBlock = TemplateBlock.create('sayhello', function(block) {
|
var templateBlock = TemplateBlock.create('sayhello', function(block) {
|
||||||
return '<p>Hello, World!</p>';
|
return 'Hello';
|
||||||
|
});
|
||||||
|
|
||||||
|
var blocks = {};
|
||||||
|
|
||||||
|
// Create a fresh Nunjucks environment
|
||||||
|
var env = new nunjucks.Environment(null, { autoescape: false });
|
||||||
|
|
||||||
|
// Add template block to environement
|
||||||
|
var Ext = templateBlock.toNunjucksExt({}, blocks);
|
||||||
|
env.addExtension(templateBlock.getExtensionName(), new Ext());
|
||||||
|
|
||||||
|
// Render a template using the block
|
||||||
|
var src = '{% sayhello %}{% endsayhello %}';
|
||||||
|
return Promise.nfcall(env.renderString.bind(env), src)
|
||||||
|
.then(function(res) {
|
||||||
|
blocks = Immutable.fromJS(blocks);
|
||||||
|
expect(blocks.size).toBe(1);
|
||||||
|
|
||||||
|
var blockId = blocks.keySeq().get(0);
|
||||||
|
var block = blocks.get(blockId);
|
||||||
|
|
||||||
|
expect(res).toBe('{{-%' + blockId + '%-}}');
|
||||||
|
expect(block.get('body')).toBe('Hello');
|
||||||
|
expect(block.get('name')).toBe('sayhello');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('must create a valid nunjucks extension', function() {
|
||||||
|
var templateBlock = TemplateBlock.create('sayhello', function(block) {
|
||||||
|
return {
|
||||||
|
body: '<p>Hello, World!</p>',
|
||||||
|
parse: true
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create a fresh Nunjucks environment
|
// Create a fresh Nunjucks environment
|
||||||
@@ -82,9 +120,12 @@ describe('TemplateBlock', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('must apply block arguments correctly', function() {
|
it('must apply block arguments correctly', function() {
|
||||||
var templateBlock = TemplateBlock.create('sayhello', function(block) {
|
var templateBlock = TemplateBlock.create('sayhello', function(block) {
|
||||||
return '<'+block.kwargs.tag+'>Hello, '+block.kwargs.name+'!</'+block.kwargs.tag+'>';
|
return {
|
||||||
|
body: '<'+block.kwargs.tag+'>Hello, '+block.kwargs.name+'!</'+block.kwargs.tag+'>',
|
||||||
|
parse: true
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create a fresh Nunjucks environment
|
// Create a fresh Nunjucks environment
|
||||||
@@ -102,11 +143,14 @@ describe('TemplateBlock', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('must accept an async function', function() {
|
it('must accept an async function', function() {
|
||||||
var templateBlock = TemplateBlock.create('sayhello', function(block) {
|
var templateBlock = TemplateBlock.create('sayhello', function(block) {
|
||||||
return Promise()
|
return Promise()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return 'Hello ' + block.body;
|
return {
|
||||||
|
body: 'Hello ' + block.body,
|
||||||
|
parse: true
|
||||||
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -125,7 +169,7 @@ describe('TemplateBlock', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('must handle nested blocks', function() {
|
it('must handle nested blocks', function() {
|
||||||
var templateBlock = new TemplateBlock({
|
var templateBlock = new TemplateBlock({
|
||||||
name: 'yoda',
|
name: 'yoda',
|
||||||
blocks: Immutable.List(['start', 'end']),
|
blocks: Immutable.List(['start', 'end']),
|
||||||
@@ -136,7 +180,10 @@ describe('TemplateBlock', function() {
|
|||||||
nested[blk.name] = blk.body.trim();
|
nested[blk.name] = blk.body.trim();
|
||||||
});
|
});
|
||||||
|
|
||||||
return '<p class="yoda">'+nested.end+' '+nested.start+'</p>';
|
return {
|
||||||
|
body: '<p class="yoda">'+nested.end+' '+nested.start+'</p>',
|
||||||
|
parse: true
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+29
-6
@@ -1,6 +1,5 @@
|
|||||||
var path = require('path');
|
var path = require('path');
|
||||||
var Immutable = require('immutable');
|
var Immutable = require('immutable');
|
||||||
var Ignore = require('ignore');
|
|
||||||
|
|
||||||
var Logger = require('../utils/logger');
|
var Logger = require('../utils/logger');
|
||||||
|
|
||||||
@@ -10,7 +9,7 @@ var Readme = require('./readme');
|
|||||||
var Summary = require('./summary');
|
var Summary = require('./summary');
|
||||||
var Glossary = require('./glossary');
|
var Glossary = require('./glossary');
|
||||||
var Languages = require('./languages');
|
var Languages = require('./languages');
|
||||||
|
var Ignore = require('./ignore');
|
||||||
|
|
||||||
var Book = Immutable.Record({
|
var Book = Immutable.Record({
|
||||||
// Logger for outptu message
|
// Logger for outptu message
|
||||||
@@ -128,8 +127,7 @@ Book.prototype.isFileIgnored = function(filename) {
|
|||||||
filename = path.join(language, filename);
|
filename = path.join(language, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ignore.isFileIgnored(filename);
|
||||||
return ignore.filter([filename]).length == 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -177,6 +175,17 @@ Book.prototype.isLanguageBook = function() {
|
|||||||
return Boolean(this.getLanguage());
|
return Boolean(this.getLanguage());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return a languages book
|
||||||
|
|
||||||
|
@param {String} language
|
||||||
|
@return {Book}
|
||||||
|
*/
|
||||||
|
Book.prototype.getLanguageBook = function(language) {
|
||||||
|
var books = this.getBooks();
|
||||||
|
return books.get(language);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Add a new language book
|
Add a new language book
|
||||||
|
|
||||||
@@ -221,6 +230,16 @@ Book.prototype.setConfig = function(config) {
|
|||||||
return this.set('config', config);
|
return this.set('config', config);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Set the ignore instance for this book
|
||||||
|
|
||||||
|
@param {Ignore}
|
||||||
|
@return {Book}
|
||||||
|
*/
|
||||||
|
Book.prototype.setIgnore = function(ignore) {
|
||||||
|
return this.set('ignore', ignore);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Change log level
|
Change log level
|
||||||
|
|
||||||
@@ -305,12 +324,16 @@ Book.prototype.getDefaultGlossaryPath = function() {
|
|||||||
*/
|
*/
|
||||||
Book.createFromParent = function createFromParent(parent, language) {
|
Book.createFromParent = function createFromParent(parent, language) {
|
||||||
var ignore = parent.getIgnore();
|
var ignore = parent.getIgnore();
|
||||||
|
var config = parent.getConfig();
|
||||||
|
|
||||||
|
// Set language in configuration
|
||||||
|
config = config.setValue('language', language);
|
||||||
|
|
||||||
return new Book({
|
return new Book({
|
||||||
// Inherits config. logegr and list of ignored files
|
// Inherits config. logegr and list of ignored files
|
||||||
logger: parent.getLogger(),
|
logger: parent.getLogger(),
|
||||||
config: parent.getConfig(),
|
config: config,
|
||||||
ignore: Ignore().add(ignore),
|
ignore: ignore,
|
||||||
|
|
||||||
language: language,
|
language: language,
|
||||||
fs: FS.reduceScope(parent.getContentFS(), language)
|
fs: FS.reduceScope(parent.getContentFS(), language)
|
||||||
|
|||||||
+55
-15
@@ -18,6 +18,16 @@ Config.prototype.getValues = function() {
|
|||||||
return this.get('values');
|
return this.get('values');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Change the file for the configuration
|
||||||
|
|
||||||
|
@param {File} file
|
||||||
|
@return {Config}
|
||||||
|
*/
|
||||||
|
Config.prototype.setFile = function(file) {
|
||||||
|
return this.set('file', file);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Return a configuration value by its key path
|
Return a configuration value by its key path
|
||||||
|
|
||||||
@@ -40,7 +50,7 @@ Config.prototype.getValue = function(keyPath, def) {
|
|||||||
|
|
||||||
@param {String} key
|
@param {String} key
|
||||||
@param {Mixed} value
|
@param {Mixed} value
|
||||||
@return {Mixed}
|
@return {Config}
|
||||||
*/
|
*/
|
||||||
Config.prototype.setValue = function(keyPath, value) {
|
Config.prototype.setValue = function(keyPath, value) {
|
||||||
keyPath = Config.keyToKeyPath(keyPath);
|
keyPath = Config.keyToKeyPath(keyPath);
|
||||||
@@ -68,6 +78,20 @@ Config.prototype.getPluginDependencies = function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return a plugin dependency by its name
|
||||||
|
|
||||||
|
@param {String} name
|
||||||
|
@return {PluginDependency}
|
||||||
|
*/
|
||||||
|
Config.prototype.getPluginDependency = function(name) {
|
||||||
|
var plugins = this.getPluginDependencies();
|
||||||
|
|
||||||
|
return plugins.find(function(dep) {
|
||||||
|
return dep.getName() === name;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Update the list of plugins dependencies
|
Update the list of plugins dependencies
|
||||||
|
|
||||||
@@ -75,11 +99,40 @@ Config.prototype.getPluginDependencies = function() {
|
|||||||
@return {Config}
|
@return {Config}
|
||||||
*/
|
*/
|
||||||
Config.prototype.setPluginDependencies = function(deps) {
|
Config.prototype.setPluginDependencies = function(deps) {
|
||||||
var plugins = PluginDependency.listFromArray(deps);
|
var plugins = PluginDependency.listToArray(deps);
|
||||||
|
|
||||||
return this.setValue('plugins', plugins);
|
return this.setValue('plugins', plugins);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Update values for an existing configuration
|
||||||
|
|
||||||
|
@param {Object} values
|
||||||
|
@returns {Config}
|
||||||
|
*/
|
||||||
|
Config.prototype.updateValues = function(values) {
|
||||||
|
values = Immutable.fromJS(values);
|
||||||
|
|
||||||
|
return this.set('values', values);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Update values for an existing configuration
|
||||||
|
|
||||||
|
@param {Config} config
|
||||||
|
@param {Object} values
|
||||||
|
@returns {Config}
|
||||||
|
*/
|
||||||
|
Config.prototype.mergeValues = function(values) {
|
||||||
|
var currentValues = this.getValues();
|
||||||
|
values = Immutable.fromJS(values);
|
||||||
|
|
||||||
|
currentValues = currentValues.mergeDeep(values);
|
||||||
|
|
||||||
|
return this.set('values', currentValues);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Create a new config for a file
|
Create a new config for a file
|
||||||
|
|
||||||
@@ -106,19 +159,6 @@ Config.createWithValues = function(values) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
Update values for an existing configuration
|
|
||||||
|
|
||||||
@param {Config} config
|
|
||||||
@param {Object} values
|
|
||||||
@returns {Config}
|
|
||||||
*/
|
|
||||||
Config.updateValues = function(config, values) {
|
|
||||||
values = Immutable.fromJS(values);
|
|
||||||
|
|
||||||
return config.set('values', values);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Convert a keyPath to an array of keys
|
Convert a keyPath to an array of keys
|
||||||
|
|||||||
+14
-8
@@ -198,23 +198,29 @@ FS.prototype.listFiles = function(dirname) {
|
|||||||
/**
|
/**
|
||||||
List all files in a directory
|
List all files in a directory
|
||||||
|
|
||||||
@param {String} dirname
|
@param {String} dirName
|
||||||
|
@param {Function(dirName)} filterFn: call it for each file/directory to test if it should stop iterating
|
||||||
@return {Promise<List<String>>}
|
@return {Promise<List<String>>}
|
||||||
*/
|
*/
|
||||||
FS.prototype.listAllFiles = function(folder) {
|
FS.prototype.listAllFiles = function(dirName, filterFn) {
|
||||||
var that = this;
|
var that = this;
|
||||||
folder = folder || '.';
|
dirName = dirName || '.';
|
||||||
|
|
||||||
return this.readDir(folder)
|
return this.readDir(dirName)
|
||||||
.then(function(files) {
|
.then(function(files) {
|
||||||
return Promise.reduce(files, function(out, file) {
|
return Promise.reduce(files, function(out, file) {
|
||||||
var isDirectory = pathIsFolder(file);
|
var isDirectory = pathIsFolder(file);
|
||||||
|
var newDirName = path.join(dirName, file);
|
||||||
|
|
||||||
if (!isDirectory) {
|
if (filterFn && filterFn(newDirName) === false) {
|
||||||
return out.push(path.join(folder, file));
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
return that.listAllFiles(path.join(folder, file))
|
if (!isDirectory) {
|
||||||
|
return out.push(newDirName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return that.listAllFiles(newDirName, filterFn)
|
||||||
.then(function(inner) {
|
.then(function(inner) {
|
||||||
return out.concat(inner);
|
return out.concat(inner);
|
||||||
});
|
});
|
||||||
@@ -223,7 +229,7 @@ FS.prototype.listAllFiles = function(folder) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Find a file in a folder (case incensitive)
|
Find a file in a folder (case insensitive)
|
||||||
Return the found filename
|
Return the found filename
|
||||||
|
|
||||||
@param {String} dirname
|
@param {String} dirname
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
var Immutable = require('immutable');
|
||||||
|
var IgnoreMutable = require('ignore');
|
||||||
|
|
||||||
|
/*
|
||||||
|
Immutable version of node-ignore
|
||||||
|
*/
|
||||||
|
var Ignore = Immutable.Record({
|
||||||
|
ignore: new IgnoreMutable()
|
||||||
|
}, 'Ignore');
|
||||||
|
|
||||||
|
Ignore.prototype.getIgnore = function() {
|
||||||
|
return this.get('ignore');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Test if a file is ignored by these rules
|
||||||
|
|
||||||
|
@param {String} filePath
|
||||||
|
@return {Boolean}
|
||||||
|
*/
|
||||||
|
Ignore.prototype.isFileIgnored = function(filename) {
|
||||||
|
var ignore = this.getIgnore();
|
||||||
|
return ignore.filter([filename]).length == 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Add rules
|
||||||
|
|
||||||
|
@param {String}
|
||||||
|
@return {Ignore}
|
||||||
|
*/
|
||||||
|
Ignore.prototype.add = function(rule) {
|
||||||
|
var ignore = this.getIgnore();
|
||||||
|
var newIgnore = new IgnoreMutable();
|
||||||
|
|
||||||
|
newIgnore.add(ignore);
|
||||||
|
newIgnore.add(rule);
|
||||||
|
|
||||||
|
return this.set('ignore', newIgnore);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Ignore;
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
var Immutable = require('immutable');
|
var Immutable = require('immutable');
|
||||||
|
|
||||||
var Book = require('./book');
|
var Book = require('./book');
|
||||||
|
var LocationUtils = require('../utils/location');
|
||||||
|
|
||||||
var Output = Immutable.Record({
|
var Output = Immutable.Record({
|
||||||
book: Book(),
|
book: Book(),
|
||||||
@@ -52,6 +53,19 @@ Output.prototype.getState = function() {
|
|||||||
return this.get('state');
|
return this.get('state');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return a page byt its file path
|
||||||
|
|
||||||
|
@param {String} filePath
|
||||||
|
@return {Page|undefined}
|
||||||
|
*/
|
||||||
|
Output.prototype.getPage = function(filePath) {
|
||||||
|
filePath = LocationUtils.normalize(filePath);
|
||||||
|
|
||||||
|
var pages = this.getPages();
|
||||||
|
return pages.get(filePath);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get root folder for output
|
Get root folder for output
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,11 @@ Parser.prototype.parsePage = function(content) {
|
|||||||
return Promise(page(content));
|
return Promise(page(content));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Parser.prototype.parseInline = function(content) {
|
||||||
|
var inline = this.get('inline');
|
||||||
|
return Promise(inline(content));
|
||||||
|
};
|
||||||
|
|
||||||
Parser.prototype.parseLanguages = function(content) {
|
Parser.prototype.parseLanguages = function(content) {
|
||||||
var langs = this.get('langs');
|
var langs = this.get('langs');
|
||||||
return Promise(langs(content));
|
return Promise(langs(content));
|
||||||
|
|||||||
@@ -29,6 +29,24 @@ PluginDependency.prototype.isEnabled = function() {
|
|||||||
return this.get('enabled');
|
return this.get('enabled');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Create a plugin with a name and a plugin
|
||||||
|
|
||||||
|
@param {String}
|
||||||
|
@return {Plugin|undefined}
|
||||||
|
*/
|
||||||
|
PluginDependency.create = function(name, version, enabled) {
|
||||||
|
if (is.undefined(enabled)) {
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PluginDependency({
|
||||||
|
name: name,
|
||||||
|
version: version || DEFAULT_VERSION,
|
||||||
|
enabled: Boolean(enabled)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Create a plugin from a string
|
Create a plugin from a string
|
||||||
|
|
||||||
@@ -90,15 +108,15 @@ PluginDependency.listFromArray = function(arr) {
|
|||||||
/**
|
/**
|
||||||
Export plugin dependencies as an array
|
Export plugin dependencies as an array
|
||||||
|
|
||||||
@param {List<PluginDependency>}
|
@param {List<PluginDependency>} list
|
||||||
@return {Array<String>}
|
@return {Array<String>}
|
||||||
*/
|
*/
|
||||||
PluginDependency.listToArray = function(arr) {
|
PluginDependency.listToArray = function(list) {
|
||||||
return arr
|
return list
|
||||||
.map(function(dep) {
|
.map(function(dep) {
|
||||||
var result;
|
var result = '';
|
||||||
|
|
||||||
if (dep.isEnabled()) {
|
if (!dep.isEnabled()) {
|
||||||
result += '-';
|
result += '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,12 @@ Summary.prototype.getByLevel = function(level) {
|
|||||||
*/
|
*/
|
||||||
Summary.prototype.getByPath = function(filePath) {
|
Summary.prototype.getByPath = function(filePath) {
|
||||||
return this.getArticle(function(article) {
|
return this.getArticle(function(article) {
|
||||||
return (LocationUtils.areIdenticalPaths(article.getPath(), filePath));
|
var articlePath = article.getPath();
|
||||||
|
|
||||||
|
return (
|
||||||
|
articlePath &&
|
||||||
|
LocationUtils.areIdenticalPaths(articlePath, filePath)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -30,12 +30,13 @@ SummaryArticle.prototype.getArticles = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Return how deep the article is
|
Return how deep the article is.
|
||||||
|
The README has a depth of 1
|
||||||
|
|
||||||
@return {Number}
|
@return {Number}
|
||||||
*/
|
*/
|
||||||
SummaryArticle.prototype.getDepth = function() {
|
SummaryArticle.prototype.getDepth = function() {
|
||||||
return this.getLevel().split('.').length;
|
return (this.getLevel().split('.').length - 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,7 +54,6 @@ SummaryArticle.prototype.getPath = function() {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var parts = ref.split('#');
|
var parts = ref.split('#');
|
||||||
|
|
||||||
var pathname = (parts.length > 1? parts.slice(0, -1).join('#') : ref);
|
var pathname = (parts.length > 1? parts.slice(0, -1).join('#') : ref);
|
||||||
|
|||||||
@@ -22,19 +22,13 @@ var TemplateBlock = Immutable.Record({
|
|||||||
blocks: Immutable.List(),
|
blocks: Immutable.List(),
|
||||||
|
|
||||||
// List of shortcuts to replace with this block
|
// List of shortcuts to replace with this block
|
||||||
shortcuts: Immutable.Map(),
|
shortcuts: Immutable.Map()
|
||||||
|
|
||||||
parse: true
|
|
||||||
}, 'TemplateBlock');
|
}, 'TemplateBlock');
|
||||||
|
|
||||||
TemplateBlock.prototype.getName = function() {
|
TemplateBlock.prototype.getName = function() {
|
||||||
return this.get('name');
|
return this.get('name');
|
||||||
};
|
};
|
||||||
|
|
||||||
TemplateBlock.prototype.getParse = function() {
|
|
||||||
return this.get('parse');
|
|
||||||
};
|
|
||||||
|
|
||||||
TemplateBlock.prototype.getEndTag = function() {
|
TemplateBlock.prototype.getEndTag = function() {
|
||||||
return this.get('end') || ('end' + this.getName());
|
return this.get('end') || ('end' + this.getName());
|
||||||
};
|
};
|
||||||
@@ -77,6 +71,8 @@ TemplateBlock.prototype.getExtensionName = function() {
|
|||||||
@return {Nunjucks.Extension}
|
@return {Nunjucks.Extension}
|
||||||
*/
|
*/
|
||||||
TemplateBlock.prototype.toNunjucksExt = function(mainContext, blocksOutput) {
|
TemplateBlock.prototype.toNunjucksExt = function(mainContext, blocksOutput) {
|
||||||
|
blocksOutput = blocksOutput || {};
|
||||||
|
|
||||||
var that = this;
|
var that = this;
|
||||||
var name = this.getName();
|
var name = this.getName();
|
||||||
var endTag = this.getEndTag();
|
var endTag = this.getEndTag();
|
||||||
@@ -241,9 +237,8 @@ TemplateBlock.prototype.normalizeBlockResult = function(result) {
|
|||||||
@return {String}
|
@return {String}
|
||||||
*/
|
*/
|
||||||
TemplateBlock.prototype.blockResultToHtml = function(result, blocksOutput) {
|
TemplateBlock.prototype.blockResultToHtml = function(result, blocksOutput) {
|
||||||
var parse = this.getParse();
|
|
||||||
var indexedKey;
|
var indexedKey;
|
||||||
var toIndex = (!parse) || (result.post !== undefined);
|
var toIndex = (!result.parse) || (result.post !== undefined);
|
||||||
|
|
||||||
if (toIndex) {
|
if (toIndex) {
|
||||||
indexedKey = genKey();
|
indexedKey = genKey();
|
||||||
@@ -251,7 +246,7 @@ TemplateBlock.prototype.blockResultToHtml = function(result, blocksOutput) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parsable block, just return it
|
// Parsable block, just return it
|
||||||
if (parse) {
|
if (result.parse) {
|
||||||
return result.body;
|
return result.body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
var addPlugin = require('../addPlugin');
|
||||||
|
var Config = require('../../../models/config');
|
||||||
|
var Book = require('../../../models/book');
|
||||||
|
|
||||||
|
describe('addPlugin', function() {
|
||||||
|
var config = Config.createWithValues({
|
||||||
|
plugins: ['hello', 'world', '-disabled']
|
||||||
|
});
|
||||||
|
var book = Book().setConfig(config);
|
||||||
|
|
||||||
|
it('should have correct state of dependencies', function() {
|
||||||
|
var disabledDep = config.getPluginDependency('disabled');
|
||||||
|
|
||||||
|
expect(disabledDep).toBeDefined();
|
||||||
|
expect(disabledDep.getVersion()).toEqual('*');
|
||||||
|
expect(disabledDep.isEnabled()).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add the plugin to the list', function() {
|
||||||
|
var newBook = addPlugin(book, 'test');
|
||||||
|
var newConfig = newBook.getConfig();
|
||||||
|
|
||||||
|
var testDep = newConfig.getPluginDependency('test');
|
||||||
|
expect(testDep).toBeDefined();
|
||||||
|
expect(testDep.getVersion()).toEqual('*');
|
||||||
|
expect(testDep.isEnabled()).toBeTruthy();
|
||||||
|
|
||||||
|
var disabledDep = newConfig.getPluginDependency('disabled');
|
||||||
|
expect(disabledDep).toBeDefined();
|
||||||
|
expect(disabledDep.getVersion()).toEqual('*');
|
||||||
|
expect(disabledDep.isEnabled()).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -11,10 +11,7 @@ function addPlugin(book, plugin, version) {
|
|||||||
var config = book.getConfig();
|
var config = book.getConfig();
|
||||||
var deps = config.getPluginDependencies();
|
var deps = config.getPluginDependencies();
|
||||||
|
|
||||||
var dep = PluginDependency({
|
var dep = PluginDependency.create(plugin, version);
|
||||||
name: plugin,
|
|
||||||
version: version
|
|
||||||
});
|
|
||||||
|
|
||||||
deps = deps.push(dep);
|
deps = deps.push(dep);
|
||||||
config = config.setPluginDependencies(deps);
|
config = config.setPluginDependencies(deps);
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
var Summary = require('../../../models/summary');
|
||||||
|
var SummaryArticle = require('../../../models/summaryArticle');
|
||||||
|
var File = require('../../../models/file');
|
||||||
|
|
||||||
|
describe('insertArticle', function() {
|
||||||
|
var insertArticle = require('../insertArticle');
|
||||||
|
var summary = Summary.createFromParts(File(), [
|
||||||
|
{
|
||||||
|
articles: [
|
||||||
|
{
|
||||||
|
title: '1.1',
|
||||||
|
path: '1.1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '1.2',
|
||||||
|
path: '1.2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Part I',
|
||||||
|
articles: [
|
||||||
|
{
|
||||||
|
title: '2.1',
|
||||||
|
path: '2.1',
|
||||||
|
articles: [
|
||||||
|
{
|
||||||
|
title: '2.1.1',
|
||||||
|
path: '2.1.1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '2.1.2',
|
||||||
|
path: '2.1.2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '2.2',
|
||||||
|
path: '2.2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
it('should insert an article at a given level', function() {
|
||||||
|
var article = SummaryArticle.create({
|
||||||
|
title: 'Inserted'
|
||||||
|
}, 'fake.level');
|
||||||
|
|
||||||
|
var newSummary = insertArticle(summary, article, '2.1.1');
|
||||||
|
|
||||||
|
var inserted = newSummary.getByLevel('2.1.1');
|
||||||
|
var nextOne = newSummary.getByLevel('2.1.2');
|
||||||
|
|
||||||
|
expect(inserted.getTitle()).toBe('Inserted');
|
||||||
|
expect(inserted.getLevel()).toBe('2.1.1');
|
||||||
|
|
||||||
|
expect(nextOne.getTitle()).toBe('2.1.1');
|
||||||
|
expect(nextOne.getLevel()).toBe('2.1.2');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should insert an article in last position', function() {
|
||||||
|
var article = SummaryArticle.create({
|
||||||
|
title: 'Inserted'
|
||||||
|
}, 'fake.level');
|
||||||
|
|
||||||
|
var newSummary = insertArticle(summary, article, '2.2');
|
||||||
|
|
||||||
|
var inserted = newSummary.getByLevel('2.2');
|
||||||
|
var previousOne = newSummary.getByLevel('2.1');
|
||||||
|
|
||||||
|
expect(inserted.getTitle()).toBe('Inserted');
|
||||||
|
expect(inserted.getLevel()).toBe('2.2');
|
||||||
|
|
||||||
|
expect(previousOne.getTitle()).toBe('2.1'); // Unchanged
|
||||||
|
expect(previousOne.getLevel()).toBe('2.1');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -42,7 +42,7 @@ describe('moveArticle', function() {
|
|||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
it('should move an article at in place', function() {
|
it('should move an article to the same place', function() {
|
||||||
var newSummary = moveArticle(summary, '2.1', '2.1');
|
var newSummary = moveArticle(summary, '2.1', '2.1');
|
||||||
|
|
||||||
expect(Immutable.is(summary, newSummary)).toBe(true);
|
expect(Immutable.is(summary, newSummary)).toBe(true);
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
var Immutable = require('immutable');
|
||||||
|
var Summary = require('../../../models/summary');
|
||||||
|
var File = require('../../../models/file');
|
||||||
|
|
||||||
|
describe('moveArticleAfter', function() {
|
||||||
|
var moveArticleAfter = require('../moveArticleAfter');
|
||||||
|
var summary = Summary.createFromParts(File(), [
|
||||||
|
{
|
||||||
|
articles: [
|
||||||
|
{
|
||||||
|
title: '1.1',
|
||||||
|
path: '1.1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '1.2',
|
||||||
|
path: '1.2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Part I',
|
||||||
|
articles: [
|
||||||
|
{
|
||||||
|
title: '2.1',
|
||||||
|
path: '2.1',
|
||||||
|
articles: [
|
||||||
|
{
|
||||||
|
title: '2.1.1',
|
||||||
|
path: '2.1.1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '2.1.2',
|
||||||
|
path: '2.1.2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '2.2',
|
||||||
|
path: '2.2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
it('moving right after itself should be invariant', function() {
|
||||||
|
var newSummary = moveArticleAfter(summary, '2.1', '2.1');
|
||||||
|
|
||||||
|
expect(Immutable.is(summary, newSummary)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('moving after previous one should be invariant too', function() {
|
||||||
|
var newSummary = moveArticleAfter(summary, '2.1', '2.0');
|
||||||
|
|
||||||
|
expect(Immutable.is(summary, newSummary)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should move an article after a previous level', function() {
|
||||||
|
var newSummary = moveArticleAfter(summary, '2.2', '2.0');
|
||||||
|
var moved = newSummary.getByLevel('2.1');
|
||||||
|
|
||||||
|
expect(moved.getTitle()).toBe('2.2');
|
||||||
|
expect(newSummary.getByLevel('2.2').getTitle()).toBe('2.1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should move an article after a previous and less deep level', function() {
|
||||||
|
var newSummary = moveArticleAfter(summary, '2.1.1', '2.0');
|
||||||
|
var moved = newSummary.getByLevel('2.1');
|
||||||
|
|
||||||
|
expect(moved.getTitle()).toBe('2.1.1');
|
||||||
|
expect(newSummary.getByLevel('2.2.1').getTitle()).toBe('2.1.2');
|
||||||
|
expect(newSummary.getByLevel('2.2').getTitle()).toBe('2.1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should move an article after a next level', function() {
|
||||||
|
var newSummary = moveArticleAfter(summary, '2.1', '2.2');
|
||||||
|
var moved = newSummary.getByLevel('2.2');
|
||||||
|
|
||||||
|
expect(moved.getTitle()).toBe('2.1');
|
||||||
|
expect(newSummary.getByLevel('2.1').getTitle()).toBe('2.2');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
var Summary = require('../../../models/summary');
|
||||||
|
var File = require('../../../models/file');
|
||||||
|
|
||||||
|
describe('removeArticle', function() {
|
||||||
|
var removeArticle = require('../removeArticle');
|
||||||
|
var summary = Summary.createFromParts(File(), [
|
||||||
|
{
|
||||||
|
articles: [
|
||||||
|
{
|
||||||
|
title: '1.1',
|
||||||
|
path: '1.1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '1.2',
|
||||||
|
path: '1.2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Part I',
|
||||||
|
articles: [
|
||||||
|
{
|
||||||
|
title: '2.1',
|
||||||
|
path: '2.1',
|
||||||
|
articles: [
|
||||||
|
{
|
||||||
|
title: '2.1.1',
|
||||||
|
path: '2.1.1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '2.1.2',
|
||||||
|
path: '2.1.2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '2.2',
|
||||||
|
path: '2.2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
it('should remove an article at a given level', function() {
|
||||||
|
var newSummary = removeArticle(summary, '2.1.1');
|
||||||
|
|
||||||
|
var removed = newSummary.getByLevel('2.1.1');
|
||||||
|
var nextOne = newSummary.getByLevel('2.1.2');
|
||||||
|
|
||||||
|
expect(removed.getTitle()).toBe('2.1.2');
|
||||||
|
expect(nextOne).toBe(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
var mergeAtLevel = require('./mergeAtLevel');
|
||||||
|
|
||||||
|
/**
|
||||||
|
Edit the ref of an article
|
||||||
|
|
||||||
|
@param {Summary} summary
|
||||||
|
@param {String} level
|
||||||
|
@param {String} newRef
|
||||||
|
@return {Summary}
|
||||||
|
*/
|
||||||
|
function editArticleRef(summary, level, newRef) {
|
||||||
|
return mergeAtLevel(summary, level, {
|
||||||
|
ref: newRef
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = editArticleRef;
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
insertArticle: require('./insertArticle'),
|
insertArticle: require('./insertArticle'),
|
||||||
moveArticle: require('./moveArticle'),
|
moveArticle: require('./moveArticle'),
|
||||||
|
moveArticleAfter: require('./moveArticleAfter'),
|
||||||
removeArticle: require('./removeArticle'),
|
removeArticle: require('./removeArticle'),
|
||||||
unshiftArticle: require('./unshiftArticle'),
|
unshiftArticle: require('./unshiftArticle'),
|
||||||
|
editArticleTitle: require('./editArticleTitle'),
|
||||||
|
editArticleRef: require('./editArticleRef'),
|
||||||
|
|
||||||
editPartTitle: require('./editPartTitle'),
|
insertPart: require('./insertPart'),
|
||||||
editArticleTitle: require('./editArticleTitle')
|
removePart: require('./removePart'),
|
||||||
|
editPartTitle: require('./editPartTitle')
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ var indexArticleLevels = require('./indexArticleLevels');
|
|||||||
subsequent article shifted.
|
subsequent article shifted.
|
||||||
|
|
||||||
@param {Summary} summary
|
@param {Summary} summary
|
||||||
@param {String|Article} level: level to insert at
|
|
||||||
@param {Article} article
|
@param {Article} article
|
||||||
|
@param {String|Article} level: level to insert at
|
||||||
@return {Summary}
|
@return {Summary}
|
||||||
*/
|
*/
|
||||||
function insertArticle(summary, level, article) {
|
function insertArticle(summary, article, level) {
|
||||||
article = SummaryArticle(article);
|
article = SummaryArticle(article);
|
||||||
level = is.string(level)? level : level.getLevel();
|
level = is.string(level)? level : level.getLevel();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
var SummaryPart = require('../../models/summaryPart');
|
||||||
|
var indexLevels = require('./indexLevels');
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a new Summary with a part inserted at given index
|
||||||
|
|
||||||
|
@param {Summary} summary
|
||||||
|
@param {Part} part
|
||||||
|
@param {Number} index
|
||||||
|
@return {Summary}
|
||||||
|
*/
|
||||||
|
function insertPart(summary, part, index) {
|
||||||
|
part = SummaryPart(part);
|
||||||
|
|
||||||
|
var parts = summary.getParts().insert(index, part);
|
||||||
|
return indexLevels(summary.set('parts', parts));
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = insertPart;
|
||||||
@@ -15,68 +15,11 @@ function moveArticle(summary, origin, target) {
|
|||||||
// Coerce to level
|
// Coerce to level
|
||||||
var originLevel = is.string(origin)? origin : origin.getLevel();
|
var originLevel = is.string(origin)? origin : origin.getLevel();
|
||||||
var targetLevel = is.string(target)? target : target.getLevel();
|
var targetLevel = is.string(target)? target : target.getLevel();
|
||||||
|
|
||||||
var article = summary.getByLevel(originLevel);
|
var article = summary.getByLevel(originLevel);
|
||||||
|
|
||||||
// Remove
|
// Remove first
|
||||||
var removed = removeArticle(summary, origin);
|
var removed = removeArticle(summary, originLevel);
|
||||||
|
return insertArticle(removed, article, targetLevel);
|
||||||
// Adjust targetLevel if removing impacted it
|
|
||||||
targetLevel = arrayToLevel(
|
|
||||||
shiftLevel(levelToArray(originLevel),
|
|
||||||
levelToArray(targetLevel)));
|
|
||||||
// Re-insert
|
|
||||||
return insertArticle(removed, target, article);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@param {Array<Number>} removedLevel
|
|
||||||
@param {Array<Number>} level The level to udpate
|
|
||||||
@return {Array<Number>}
|
|
||||||
*/
|
|
||||||
function shiftLevel(removedLevel, level) {
|
|
||||||
if (level.length === 0) {
|
|
||||||
// `removedLevel` is under level, so no effect
|
|
||||||
return level;
|
|
||||||
} else if (removedLevel.length === 0) {
|
|
||||||
// Either `level` is a child of `removedLevel`... or they are equal
|
|
||||||
// This is undefined behavior.
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
|
|
||||||
var removedRoot = removedLevel[0];
|
|
||||||
var root = level[0];
|
|
||||||
var removedRest = removedLevel.slice(1);
|
|
||||||
var rest = level.slice(1);
|
|
||||||
|
|
||||||
if (removedRoot < root) {
|
|
||||||
// It will shift levels at this point. The rest is unchanged.
|
|
||||||
return Array.prototype.concat(root - 1, rest);
|
|
||||||
} else if (removedRoot === root) {
|
|
||||||
// Look deeper
|
|
||||||
return Array.prototype.concat(root, shiftLevel(removedRest, rest));
|
|
||||||
} else {
|
|
||||||
// No impact
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@param {String}
|
|
||||||
@return {Array<Number>}
|
|
||||||
*/
|
|
||||||
function levelToArray(l) {
|
|
||||||
return l.split('.').map(function (char) {
|
|
||||||
return parseInt(char, 10);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@param {Array<Number>}
|
|
||||||
@return {String}
|
|
||||||
*/
|
|
||||||
function arrayToLevel(a) {
|
|
||||||
return a.join('.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = moveArticle;
|
module.exports = moveArticle;
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
var is = require('is');
|
||||||
|
var removeArticle = require('./removeArticle');
|
||||||
|
var insertArticle = require('./insertArticle');
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a new summary, with the an article moved after another
|
||||||
|
article. Unlike `moveArticle`, does not ensure that the article
|
||||||
|
will be found at the target's level plus one.
|
||||||
|
|
||||||
|
@param {Summary} summary
|
||||||
|
@param {String|SummaryArticle} origin
|
||||||
|
@param {String|SummaryArticle} afterTarget
|
||||||
|
@return {Summary}
|
||||||
|
*/
|
||||||
|
function moveArticleAfter(summary, origin, afterTarget) {
|
||||||
|
// Coerce to level
|
||||||
|
var originLevel = is.string(origin)? origin : origin.getLevel();
|
||||||
|
var afterTargetLevel = is.string(afterTarget)? afterTarget : afterTarget.getLevel();
|
||||||
|
var article = summary.getByLevel(originLevel);
|
||||||
|
|
||||||
|
var targetLevel = increment(afterTargetLevel);
|
||||||
|
|
||||||
|
if (targetLevel < origin) {
|
||||||
|
// Remove first
|
||||||
|
var removed = removeArticle(summary, originLevel);
|
||||||
|
// Insert then
|
||||||
|
return insertArticle(removed, article, targetLevel);
|
||||||
|
} else {
|
||||||
|
// Insert right after first
|
||||||
|
var inserted = insertArticle(summary, article, targetLevel);
|
||||||
|
// Remove old one
|
||||||
|
return removeArticle(inserted, originLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@param {String}
|
||||||
|
@return {Array<Number>}
|
||||||
|
*/
|
||||||
|
function levelToArray(l) {
|
||||||
|
return l.split('.').map(function (char) {
|
||||||
|
return parseInt(char, 10);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@param {Array<Number>}
|
||||||
|
@return {String}
|
||||||
|
*/
|
||||||
|
function arrayToLevel(a) {
|
||||||
|
return a.join('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
function increment(level) {
|
||||||
|
level = levelToArray(level);
|
||||||
|
level[level.length - 1]++;
|
||||||
|
return arrayToLevel(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = moveArticleAfter;
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
var indexLevels = require('./indexLevels');
|
||||||
|
|
||||||
|
/**
|
||||||
|
Remove a part at given index
|
||||||
|
|
||||||
|
@param {Summary} summary
|
||||||
|
@param {Number|} index
|
||||||
|
@return {Summary}
|
||||||
|
*/
|
||||||
|
function removePart(summary, index) {
|
||||||
|
var parts = summary.getParts().remove(index);
|
||||||
|
return indexLevels(summary.set('parts', parts));
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = removePart;
|
||||||
@@ -3,7 +3,7 @@ var EbookGenerator = require('../ebook');
|
|||||||
|
|
||||||
describe('EbookGenerator', function() {
|
describe('EbookGenerator', function() {
|
||||||
|
|
||||||
pit('should generate a SUMMARY.html', function() {
|
it('should generate a SUMMARY.html', function() {
|
||||||
return generateMock(EbookGenerator, {
|
return generateMock(EbookGenerator, {
|
||||||
'README.md': 'Hello World'
|
'README.md': 'Hello World'
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ var JSONGenerator = require('../json');
|
|||||||
|
|
||||||
describe('JSONGenerator', function() {
|
describe('JSONGenerator', function() {
|
||||||
|
|
||||||
pit('should generate a README.json', function() {
|
it('should generate a README.json', function() {
|
||||||
return generateMock(JSONGenerator, {
|
return generateMock(JSONGenerator, {
|
||||||
'README.md': 'Hello World'
|
'README.md': 'Hello World'
|
||||||
})
|
})
|
||||||
@@ -12,7 +12,7 @@ describe('JSONGenerator', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should generate a json file for each articles', function() {
|
it('should generate a json file for each articles', function() {
|
||||||
return generateMock(JSONGenerator, {
|
return generateMock(JSONGenerator, {
|
||||||
'README.md': 'Hello World',
|
'README.md': 'Hello World',
|
||||||
'SUMMARY.md': '# Summary\n\n* [Page](test/page.md)',
|
'SUMMARY.md': '# Summary\n\n* [Page](test/page.md)',
|
||||||
@@ -25,5 +25,22 @@ describe('JSONGenerator', function() {
|
|||||||
expect(folder).toHaveFile('test/page.json');
|
expect(folder).toHaveFile('test/page.json');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should generate a multilingual book', function() {
|
||||||
|
return generateMock(JSONGenerator, {
|
||||||
|
'LANGS.md': '# Languages\n\n* [en](en)\n* [fr](fr)',
|
||||||
|
'en': {
|
||||||
|
'README.md': 'Hello'
|
||||||
|
},
|
||||||
|
'fr': {
|
||||||
|
'README.md': 'Bonjour'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(folder) {
|
||||||
|
expect(folder).toHaveFile('en/README.json');
|
||||||
|
expect(folder).toHaveFile('fr/README.json');
|
||||||
|
expect(folder).toHaveFile('README.json');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ var WebsiteGenerator = require('../website');
|
|||||||
|
|
||||||
describe('WebsiteGenerator', function() {
|
describe('WebsiteGenerator', function() {
|
||||||
|
|
||||||
pit('should generate an index.html', function() {
|
it('should generate an index.html', function() {
|
||||||
return generateMock(WebsiteGenerator, {
|
return generateMock(WebsiteGenerator, {
|
||||||
'README.md': 'Hello World'
|
'README.md': 'Hello World'
|
||||||
})
|
})
|
||||||
@@ -12,7 +12,7 @@ describe('WebsiteGenerator', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should copy asset files', function() {
|
it('should copy asset files', function() {
|
||||||
return generateMock(WebsiteGenerator, {
|
return generateMock(WebsiteGenerator, {
|
||||||
'README.md': 'Hello World',
|
'README.md': 'Hello World',
|
||||||
'myJsFile.js': 'var a = "test";',
|
'myJsFile.js': 'var a = "test";',
|
||||||
@@ -27,7 +27,7 @@ describe('WebsiteGenerator', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should generate an index.html for AsciiDoc', function() {
|
it('should generate an index.html for AsciiDoc', function() {
|
||||||
return generateMock(WebsiteGenerator, {
|
return generateMock(WebsiteGenerator, {
|
||||||
'README.adoc': 'Hello World'
|
'README.adoc': 'Hello World'
|
||||||
})
|
})
|
||||||
@@ -36,7 +36,7 @@ describe('WebsiteGenerator', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should generate an HTML file for each articles', function() {
|
it('should generate an HTML file for each articles', function() {
|
||||||
return generateMock(WebsiteGenerator, {
|
return generateMock(WebsiteGenerator, {
|
||||||
'README.md': 'Hello World',
|
'README.md': 'Hello World',
|
||||||
'SUMMARY.md': '# Summary\n\n* [Page](test/page.md)',
|
'SUMMARY.md': '# Summary\n\n* [Page](test/page.md)',
|
||||||
@@ -50,7 +50,7 @@ describe('WebsiteGenerator', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should not generate file if entry file doesn\'t exist', function() {
|
it('should not generate file if entry file doesn\'t exist', function() {
|
||||||
return generateMock(WebsiteGenerator, {
|
return generateMock(WebsiteGenerator, {
|
||||||
'README.md': 'Hello World',
|
'README.md': 'Hello World',
|
||||||
'SUMMARY.md': '# Summary\n\n* [Page 1](page.md)\n* [Page 2](test/page.md)',
|
'SUMMARY.md': '# Summary\n\n* [Page 1](page.md)\n* [Page 2](test/page.md)',
|
||||||
@@ -60,12 +60,12 @@ describe('WebsiteGenerator', function() {
|
|||||||
})
|
})
|
||||||
.then(function(folder) {
|
.then(function(folder) {
|
||||||
expect(folder).toHaveFile('index.html');
|
expect(folder).toHaveFile('index.html');
|
||||||
expect(folder).not.toHaveFile('page.html');
|
expect(folder).toNotHaveFile('page.html');
|
||||||
expect(folder).toHaveFile('test/page.html');
|
expect(folder).toHaveFile('test/page.html');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should generate a multilingual book', function() {
|
it('should generate a multilingual book', function() {
|
||||||
return generateMock(WebsiteGenerator, {
|
return generateMock(WebsiteGenerator, {
|
||||||
'LANGS.md': '# Languages\n\n* [en](en)\n* [fr](fr)',
|
'LANGS.md': '# Languages\n\n* [en](en)\n* [fr](fr)',
|
||||||
'en': {
|
'en': {
|
||||||
@@ -81,12 +81,12 @@ describe('WebsiteGenerator', function() {
|
|||||||
expect(folder).toHaveFile('fr/index.html');
|
expect(folder).toHaveFile('fr/index.html');
|
||||||
|
|
||||||
// Should not copy languages as assets
|
// Should not copy languages as assets
|
||||||
expect(folder).not.toHaveFile('en/README.md');
|
expect(folder).toNotHaveFile('en/README.md');
|
||||||
expect(folder).not.toHaveFile('fr/README.md');
|
expect(folder).toNotHaveFile('fr/README.md');
|
||||||
|
|
||||||
// Should copy assets only once
|
// Should copy assets only once
|
||||||
expect(folder).toHaveFile('gitbook/style.css');
|
expect(folder).toHaveFile('gitbook/style.css');
|
||||||
expect(folder).not.toHaveFile('en/gitbook/style.css');
|
expect(folder).toNotHaveFile('en/gitbook/style.css');
|
||||||
|
|
||||||
expect(folder).toHaveFile('index.html');
|
expect(folder).toHaveFile('index.html');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ function createTemplateEngine(output) {
|
|||||||
filters = defaultFilters.merge(filters);
|
filters = defaultFilters.merge(filters);
|
||||||
|
|
||||||
// Create loader
|
// Create loader
|
||||||
var loader = new Templating.ConrefsLoader(rootFolder, logger);
|
var transformFn = Templating.replaceShortcuts.bind(null, blocks);
|
||||||
|
var loader = new Templating.ConrefsLoader(rootFolder, transformFn, logger);
|
||||||
|
|
||||||
// Create API context
|
// Create API context
|
||||||
var context = Api.encodeGlobal(output);
|
var context = Api.encodeGlobal(output);
|
||||||
|
|||||||
@@ -11,17 +11,17 @@ function getCoverPath(output) {
|
|||||||
var outputRoot = output.getRoot();
|
var outputRoot = output.getRoot();
|
||||||
var book = output.getBook();
|
var book = output.getBook();
|
||||||
var config = book.getConfig();
|
var config = book.getConfig();
|
||||||
var cover = config.getValue('cover', 'cover.jpg');
|
var coverName = config.getValue('cover', 'cover.jpg');
|
||||||
|
|
||||||
// Resolve to absolute
|
// Resolve to absolute
|
||||||
cover = fs.pickFile(outputRoot, cover);
|
var cover = fs.pickFile(outputRoot, coverName);
|
||||||
if (cover) {
|
if (cover) {
|
||||||
return cover;
|
return cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multilingual? try parent folder
|
// Multilingual? try parent folder
|
||||||
if (book.isLanguageBook()) {
|
if (book.isLanguageBook()) {
|
||||||
cover = fs.pickFile(path.join(outputRoot, '..'), cover);
|
cover = fs.pickFile(path.join(outputRoot, '..'), coverName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cover;
|
return cover;
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ function getPDFTemplate(output, type) {
|
|||||||
var context = JSONUtils.encodeOutput(output);
|
var context = JSONUtils.encodeOutput(output);
|
||||||
context.page = {
|
context.page = {
|
||||||
num: '_PAGENUM_',
|
num: '_PAGENUM_',
|
||||||
title: '_TITLE_',
|
title: '_SECTION_'
|
||||||
section: '_SECTION_'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Render the theme
|
// Render the theme
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ var path = require('path');
|
|||||||
var Immutable = require('immutable');
|
var Immutable = require('immutable');
|
||||||
|
|
||||||
var Output = require('../models/output');
|
var Output = require('../models/output');
|
||||||
var Config = require('../models/config');
|
|
||||||
var Promise = require('../utils/promise');
|
var Promise = require('../utils/promise');
|
||||||
var fs = require('../utils/fs');
|
var fs = require('../utils/fs');
|
||||||
|
|
||||||
@@ -41,7 +40,7 @@ function processOutput(generator, startOutput) {
|
|||||||
var book = output.getBook();
|
var book = output.getBook();
|
||||||
var config = book.getConfig();
|
var config = book.getConfig();
|
||||||
|
|
||||||
config = Config.updateValues(config, result);
|
config = config.updateValues(result);
|
||||||
book = book.set('config', config);
|
book = book.set('config', config);
|
||||||
return output.set('book', book);
|
return output.set('book', book);
|
||||||
}
|
}
|
||||||
@@ -78,6 +77,7 @@ function processOutput(generator, startOutput) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var logger = book.getLogger();
|
||||||
var books = book.getBooks();
|
var books = book.getBooks();
|
||||||
var outputRoot = output.getRoot();
|
var outputRoot = output.getRoot();
|
||||||
var plugins = output.getPlugins();
|
var plugins = output.getPlugins();
|
||||||
@@ -95,6 +95,8 @@ function processOutput(generator, startOutput) {
|
|||||||
plugins: plugins
|
plugins: plugins
|
||||||
});
|
});
|
||||||
|
|
||||||
|
logger.info.ln('');
|
||||||
|
logger.info.ln('generating language "' + langBook.getLanguage() + '"');
|
||||||
return processOutput(generator, langOutput);
|
return processOutput(generator, langOutput);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var path = require('path');
|
||||||
|
|
||||||
var Promise = require('../utils/promise');
|
var Promise = require('../utils/promise');
|
||||||
var error = require('../utils/error');
|
var error = require('../utils/error');
|
||||||
var timing = require('../utils/timing');
|
var timing = require('../utils/timing');
|
||||||
@@ -21,7 +23,7 @@ function generatePage(output, page) {
|
|||||||
|
|
||||||
return timing.measure(
|
return timing.measure(
|
||||||
'page.generate',
|
'page.generate',
|
||||||
Parse.parsePage(book, page)
|
Promise(page)
|
||||||
.then(function(resultPage) {
|
.then(function(resultPage) {
|
||||||
var file = resultPage.getFile();
|
var file = resultPage.getFile();
|
||||||
var filePath = file.getPath();
|
var filePath = file.getPath();
|
||||||
@@ -44,7 +46,8 @@ function generatePage(output, page) {
|
|||||||
|
|
||||||
// Render templating syntax
|
// Render templating syntax
|
||||||
.then(function(content) {
|
.then(function(content) {
|
||||||
return Templating.render(engine, filePath, content, context);
|
var absoluteFilePath = path.join(book.getContentRoot(), filePath);
|
||||||
|
return Templating.render(engine, absoluteFilePath, content, context);
|
||||||
})
|
})
|
||||||
|
|
||||||
.then(function(output) {
|
.then(function(output) {
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ function resolveFileToURL(output, filePath) {
|
|||||||
// Convert /test.png -> test.png
|
// Convert /test.png -> test.png
|
||||||
filePath = LocationUtils.toAbsolute(filePath, '', '');
|
filePath = LocationUtils.toAbsolute(filePath, '', '');
|
||||||
|
|
||||||
var pages = output.getPages();
|
var page = output.getPage(filePath);
|
||||||
var page = pages.get(filePath);
|
|
||||||
|
|
||||||
// if file is a page, return correct .html url
|
// if file is a page, return correct .html url
|
||||||
if (page) {
|
if (page) {
|
||||||
|
|||||||
@@ -2,5 +2,6 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'json',
|
name: 'json',
|
||||||
Options: require('./options'),
|
Options: require('./options'),
|
||||||
onPage: require('./onPage')
|
onPage: require('./onPage'),
|
||||||
|
onFinish: require('./onFinish')
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ var path = require('path');
|
|||||||
|
|
||||||
var Promise = require('../../utils/promise');
|
var Promise = require('../../utils/promise');
|
||||||
var fs = require('../../utils/fs');
|
var fs = require('../../utils/fs');
|
||||||
|
var JSONUtils = require('../../json');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Finish the generation
|
Finish the generation
|
||||||
@@ -21,11 +22,25 @@ function onFinish(output) {
|
|||||||
var languages = book.getLanguages();
|
var languages = book.getLanguages();
|
||||||
var mainLanguage = languages.getDefaultLanguage();
|
var mainLanguage = languages.getDefaultLanguage();
|
||||||
|
|
||||||
// Copy README.json from it
|
// Read the main JSON
|
||||||
return fs.copy(
|
return fs.readFile(path.resolve(outputRoot, mainLanguage.getID(), 'README.json'), 'utf8')
|
||||||
path.resolve(outputRoot, mainLanguage.getID(), 'README.json'),
|
|
||||||
path.resolve(outputRoot, 'README.json')
|
// Extend the JSON
|
||||||
)
|
.then(function(content) {
|
||||||
|
var json = JSON.parse(content);
|
||||||
|
|
||||||
|
json.languages = JSONUtils.encodeLanguages(languages);
|
||||||
|
|
||||||
|
return json;
|
||||||
|
})
|
||||||
|
|
||||||
|
.then(function(json) {
|
||||||
|
return fs.writeFile(
|
||||||
|
path.resolve(outputRoot, 'README.json'),
|
||||||
|
JSON.stringify(json, null, 4)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
|
||||||
.thenResolve(output);
|
.thenResolve(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
jest.autoMockOff();
|
|
||||||
|
|
||||||
var cheerio = require('cheerio');
|
var cheerio = require('cheerio');
|
||||||
|
var addHeadingId = require('../addHeadingId');
|
||||||
|
|
||||||
describe('addHeadingId', function() {
|
describe('addHeadingId', function() {
|
||||||
var addHeadingId = require('../addHeadingId');
|
it('should add an ID if none', function() {
|
||||||
|
|
||||||
pit('should add an ID if none', function() {
|
|
||||||
var $ = cheerio.load('<h1>Hello World</h1><h2>Cool !!</h2>');
|
var $ = cheerio.load('<h1>Hello World</h1><h2>Cool !!</h2>');
|
||||||
|
|
||||||
return addHeadingId($)
|
return addHeadingId($)
|
||||||
@@ -15,7 +12,7 @@ describe('addHeadingId', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should not change existing IDs', function() {
|
it('should not change existing IDs', function() {
|
||||||
var $ = cheerio.load('<h1 id="awesome">Hello World</h1>');
|
var $ = cheerio.load('<h1 id="awesome">Hello World</h1>');
|
||||||
|
|
||||||
return addHeadingId($)
|
return addHeadingId($)
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
jest.autoMockOff();
|
|
||||||
|
|
||||||
var Immutable = require('immutable');
|
var Immutable = require('immutable');
|
||||||
var cheerio = require('cheerio');
|
var cheerio = require('cheerio');
|
||||||
var GlossaryEntry = require('../../../models/glossaryEntry');
|
var GlossaryEntry = require('../../../models/glossaryEntry');
|
||||||
|
var annotateText = require('../annotateText');
|
||||||
|
|
||||||
describe('annotateText', function() {
|
describe('annotateText', function() {
|
||||||
var annotateText = require('../annotateText');
|
|
||||||
|
|
||||||
var entries = Immutable.List([
|
var entries = Immutable.List([
|
||||||
GlossaryEntry({ name: 'Word' }),
|
GlossaryEntry({ name: 'Word' }),
|
||||||
GlossaryEntry({ name: 'Multiple Words' })
|
GlossaryEntry({ name: 'Multiple Words' })
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ describe('fetchRemoteImages', function() {
|
|||||||
dir = tmp.dirSync();
|
dir = tmp.dirSync();
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should download image file', function() {
|
it('should download image file', function() {
|
||||||
var $ = cheerio.load('<img src="' + URL + '" />');
|
var $ = cheerio.load('<img src="' + URL + '" />');
|
||||||
|
|
||||||
return fetchRemoteImages(dir.name, 'index.html', $)
|
return fetchRemoteImages(dir.name, 'index.html', $)
|
||||||
@@ -24,7 +24,7 @@ describe('fetchRemoteImages', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should download image file and replace with relative path', function() {
|
it('should download image file and replace with relative path', function() {
|
||||||
var $ = cheerio.load('<img src="' + URL + '" />');
|
var $ = cheerio.load('<img src="' + URL + '" />');
|
||||||
|
|
||||||
return fetchRemoteImages(dir.name, 'test/index.html', $)
|
return fetchRemoteImages(dir.name, 'test/index.html', $)
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
jest.autoMockOff();
|
|
||||||
|
|
||||||
var cheerio = require('cheerio');
|
var cheerio = require('cheerio');
|
||||||
var Promise = require('../../../utils/promise');
|
var Promise = require('../../../utils/promise');
|
||||||
|
var highlightCode = require('../highlightCode');
|
||||||
|
|
||||||
describe('highlightCode', function() {
|
describe('highlightCode', function() {
|
||||||
var highlightCode = require('../highlightCode');
|
|
||||||
|
|
||||||
function doHighlight(lang, code) {
|
function doHighlight(lang, code) {
|
||||||
return {
|
return {
|
||||||
text: '' + (lang || '') + '$' + code
|
text: '' + (lang || '') + '$' + code
|
||||||
@@ -19,7 +16,7 @@ describe('highlightCode', function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pit('should call it for normal code element', function() {
|
it('should call it for normal code element', function() {
|
||||||
var $ = cheerio.load('<p>This is a <code>test</code></p>');
|
var $ = cheerio.load('<p>This is a <code>test</code></p>');
|
||||||
|
|
||||||
return highlightCode(doHighlight, $)
|
return highlightCode(doHighlight, $)
|
||||||
@@ -29,7 +26,7 @@ describe('highlightCode', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should call it for markdown code block', function() {
|
it('should call it for markdown code block', function() {
|
||||||
var $ = cheerio.load('<pre><code class="lang-js">test</code></pre>');
|
var $ = cheerio.load('<pre><code class="lang-js">test</code></pre>');
|
||||||
|
|
||||||
return highlightCode(doHighlight, $)
|
return highlightCode(doHighlight, $)
|
||||||
@@ -39,7 +36,7 @@ describe('highlightCode', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should call it for asciidoc code block', function() {
|
it('should call it for asciidoc code block', function() {
|
||||||
var $ = cheerio.load('<pre><code class="language-python">test</code></pre>');
|
var $ = cheerio.load('<pre><code class="language-python">test</code></pre>');
|
||||||
|
|
||||||
return highlightCode(doHighlight, $)
|
return highlightCode(doHighlight, $)
|
||||||
@@ -49,7 +46,7 @@ describe('highlightCode', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should accept async highlighter', function() {
|
it('should accept async highlighter', function() {
|
||||||
var $ = cheerio.load('<pre><code class="language-python">test</code></pre>');
|
var $ = cheerio.load('<pre><code class="language-python">test</code></pre>');
|
||||||
|
|
||||||
return highlightCode(doHighlightAsync, $)
|
return highlightCode(doHighlightAsync, $)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ describe('inlinePng', function() {
|
|||||||
dir = tmp.dirSync();
|
dir = tmp.dirSync();
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should write an inline PNG using data URI as a file', function() {
|
it('should write an inline PNG using data URI as a file', function() {
|
||||||
var $ = cheerio.load('<img alt="GitBook Logo 20x20" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUEAYAAADdGcFOAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAAsTAAALEwEAmpwYAAABWWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgpMwidZAAAF+klEQVRIDY3Wf5CVVR3H8c9z791fyI9dQwdQ4TTI7wEWnQZZAa/mJE4Z0OaKUuN1KoaykZxUGGHay+iIVFMoEYrUPhDCKEKW2ChT8dA0RCSxWi6EW3sYYpcfxq5C+4O9957O+7m7O/qHQ9/XzH1+nHuec57z8wkWTsKw0y6N/LxXN6KzTnEUHi8eP/l3YStSU/MdsYvBbGh8six2YXcbcgc++QkfTQkWz/81KtqDA0hlUoWnsX+5uxe5X365BB9my2bjrHNHccLk16BpS9CExjcmXMDbD6wehdyEjxbjz1uK1zn9qga6dcfnMLXeXY/qjuQqTF4W1MKke8ZgeNhjMCxMPIWSd4OF78C55CFI/1kF6WwXpMqjkAZ/CKniNDrCsmU4lE1YbPlgR2x7R39FF23D4mq3A1+Z35PGTNs1E1XhxcGQOh6HNPwXkK56BVJhOaRg/pvoHXNxHFw410B25EYE2RMvI0i/twFJvXcrFObykEa+DmnQGLwYqR0l2a6JqItaj8C/4E2QxtZCofkC8tF1t8HZc/fAZaLnIF2xEsoEtW1w7vBSSFtfhDTnCki9cSi81Ain1uko2Ld+Dmf2rkUq0/5t+PYbFtPQdkjzNiAXTWtDEF49FgkzJInAVPwNyhzcDOmrdZCm/Rn+ebWtcPs+/U24hmg2XL0rRkPPELh9R8fDtXR2oC/VuZbGaci79Ajkb6lZgfyYtyzy/X9s6T/pO/ZfN/RdNxxIwTWM2wbX8KVmuIaEqmKm6zEondwGpd0SyOy5DrJ//TFkX9kMhd3XQHbEVCSsm4OECV5HIv2p15CwfWPSntoHRbv2Q1HzSvSlSqZwATIuBxk/zZBOBbdB+u9hSKU3Q7pwAjInZkFm6U8hu7MSMqe/Dqn8fUj5GVCmpxK+4N/F1LMa0p5eSOPqIPP7NGSunAI/+R6GnzQzIBt8A1LC/QZ+6HwLst1rITv0n5CtXgSZ78yFTNkR+FdeDZneJkip3fAtsQ5Scilkek7CH9dAmjIWvkK7IXXOh6/IzZDNPQdZXR1TQmdjKv0ZfEu0YKDpNflpyG5aDtnRv8VAuu3dBV+huyBbvgdS97tQNLQc0mfugKy5Cb4BipPIXvsUpK5N8Mvao/Bd3QDZRH9Rrtj3Cl6FHwPFMLmNkKrj8BnHoT+XX6f2wl+XxFS4Ab7C72Dgf7bi+5DpTkNm8kQMpCs/BzIlz8LfPxnzLdh3EjwMX4GX4Ju4GNb9A1L7k/D3J8b6kv2LFCtmCmcgUzoJsr2z4MfwFsh87xikZefg188fYaAhpPUxm3ge/vFnYkoED0HqeQiyJYcwkNGWnoNv6s9C1p1Bf/389VYoCjohW7UfMms3wXdpBv7+FEiPLIHs4DIMNERUNhbSpY3wk6QOsqlCDVx2xCrInMpBmfNPQOnzKxBkkrugdOl9GKigSZZCUWIm/GqwDtLUI5D+WAOlb9wKP0YvQLbjZSjsaYaL/n0/FA3fDtnCGihK5UYjCK+ZDr+TDIKLdm2Fs1UOzo76F5wO74XSZj0S6d7RCMLkCshcXALZxaWQRjXDZQ62oRAdCeG/Ju5HELX2QFH3C0hkRy6GovyfwF58AoVbguOxyB2H7/I34Gf11yANnQSp7Vr4MbQH0vg7kbNNp5AM3UrIVDchnz56B1Jm573wW9gZSFVPwO/hefg5FsIvN09CchtQCIOFw/F5U8ii3CZn4cqo7C8YlXEPYkx9cacZl00+iwnprrtwVdj1Q/gXmAs/pu6LZc9XQOGgSvh19n2cDZN341g2EcfxTEGwH/RewqlMsUfbbWIGLjUG+j/j9nokD1beiOvLS5dhjr30Gu6ZnivgdtM/6VJvY1+6pBHbH+h9CX84vfMxNJtisYVFlys+WNCIZJNmIsjohlhNSQC3f8R55H+y/hjkN8GPR9ndCLJxT4/3n0Px51ay8XQnNrYfDJHf//Fc0oMrEZSeeQGJ7+Z+gKCgLbHNWgXnB9FlYt5JaN38JIINC95EakjtAqQeuUx21c5B6tEFf0fSfbEFQf28Z6D6y+X/H0jf40QQJhYwAAAAAElFTkSuQmCC"/>');
|
var $ = cheerio.load('<img alt="GitBook Logo 20x20" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUEAYAAADdGcFOAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAAsTAAALEwEAmpwYAAABWWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgpMwidZAAAF+klEQVRIDY3Wf5CVVR3H8c9z791fyI9dQwdQ4TTI7wEWnQZZAa/mJE4Z0OaKUuN1KoaykZxUGGHay+iIVFMoEYrUPhDCKEKW2ChT8dA0RCSxWi6EW3sYYpcfxq5C+4O9957O+7m7O/qHQ9/XzH1+nHuec57z8wkWTsKw0y6N/LxXN6KzTnEUHi8eP/l3YStSU/MdsYvBbGh8six2YXcbcgc++QkfTQkWz/81KtqDA0hlUoWnsX+5uxe5X365BB9my2bjrHNHccLk16BpS9CExjcmXMDbD6wehdyEjxbjz1uK1zn9qga6dcfnMLXeXY/qjuQqTF4W1MKke8ZgeNhjMCxMPIWSd4OF78C55CFI/1kF6WwXpMqjkAZ/CKniNDrCsmU4lE1YbPlgR2x7R39FF23D4mq3A1+Z35PGTNs1E1XhxcGQOh6HNPwXkK56BVJhOaRg/pvoHXNxHFw410B25EYE2RMvI0i/twFJvXcrFObykEa+DmnQGLwYqR0l2a6JqItaj8C/4E2QxtZCofkC8tF1t8HZc/fAZaLnIF2xEsoEtW1w7vBSSFtfhDTnCki9cSi81Ain1uko2Ld+Dmf2rkUq0/5t+PYbFtPQdkjzNiAXTWtDEF49FgkzJInAVPwNyhzcDOmrdZCm/Rn+ebWtcPs+/U24hmg2XL0rRkPPELh9R8fDtXR2oC/VuZbGaci79Ajkb6lZgfyYtyzy/X9s6T/pO/ZfN/RdNxxIwTWM2wbX8KVmuIaEqmKm6zEondwGpd0SyOy5DrJ//TFkX9kMhd3XQHbEVCSsm4OECV5HIv2p15CwfWPSntoHRbv2Q1HzSvSlSqZwATIuBxk/zZBOBbdB+u9hSKU3Q7pwAjInZkFm6U8hu7MSMqe/Dqn8fUj5GVCmpxK+4N/F1LMa0p5eSOPqIPP7NGSunAI/+R6GnzQzIBt8A1LC/QZ+6HwLst1rITv0n5CtXgSZ78yFTNkR+FdeDZneJkip3fAtsQ5Scilkek7CH9dAmjIWvkK7IXXOh6/IzZDNPQdZXR1TQmdjKv0ZfEu0YKDpNflpyG5aDtnRv8VAuu3dBV+huyBbvgdS97tQNLQc0mfugKy5Cb4BipPIXvsUpK5N8Mvao/Bd3QDZRH9Rrtj3Cl6FHwPFMLmNkKrj8BnHoT+XX6f2wl+XxFS4Ab7C72Dgf7bi+5DpTkNm8kQMpCs/BzIlz8LfPxnzLdh3EjwMX4GX4Ju4GNb9A1L7k/D3J8b6kv2LFCtmCmcgUzoJsr2z4MfwFsh87xikZefg188fYaAhpPUxm3ge/vFnYkoED0HqeQiyJYcwkNGWnoNv6s9C1p1Bf/389VYoCjohW7UfMms3wXdpBv7+FEiPLIHs4DIMNERUNhbSpY3wk6QOsqlCDVx2xCrInMpBmfNPQOnzKxBkkrugdOl9GKigSZZCUWIm/GqwDtLUI5D+WAOlb9wKP0YvQLbjZSjsaYaL/n0/FA3fDtnCGihK5UYjCK+ZDr+TDIKLdm2Fs1UOzo76F5wO74XSZj0S6d7RCMLkCshcXALZxaWQRjXDZQ62oRAdCeG/Ju5HELX2QFH3C0hkRy6GovyfwF58AoVbguOxyB2H7/I34Gf11yANnQSp7Vr4MbQH0vg7kbNNp5AM3UrIVDchnz56B1Jm573wW9gZSFVPwO/hefg5FsIvN09CchtQCIOFw/F5U8ii3CZn4cqo7C8YlXEPYkx9cacZl00+iwnprrtwVdj1Q/gXmAs/pu6LZc9XQOGgSvh19n2cDZN341g2EcfxTEGwH/RewqlMsUfbbWIGLjUG+j/j9nokD1beiOvLS5dhjr30Gu6ZnivgdtM/6VJvY1+6pBHbH+h9CX84vfMxNJtisYVFlys+WNCIZJNmIsjohlhNSQC3f8R55H+y/hjkN8GPR9ndCLJxT4/3n0Px51ay8XQnNrYfDJHf//Fc0oMrEZSeeQGJ7+Z+gKCgLbHNWgXnB9FlYt5JaN38JIINC95EakjtAqQeuUx21c5B6tEFf0fSfbEFQf28Z6D6y+X/H0jf40QQJhYwAAAAAElFTkSuQmCC"/>');
|
||||||
|
|
||||||
return inlinePng(dir.name, 'index.html', $)
|
return inlinePng(dir.name, 'index.html', $)
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
jest.autoMockOff();
|
|
||||||
|
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var cheerio = require('cheerio');
|
var cheerio = require('cheerio');
|
||||||
|
var resolveLinks = require('../resolveLinks');
|
||||||
|
|
||||||
describe('resolveLinks', function() {
|
describe('resolveLinks', function() {
|
||||||
var resolveLinks = require('../resolveLinks');
|
|
||||||
|
|
||||||
function resolveFileBasic(href) {
|
function resolveFileBasic(href) {
|
||||||
return href;
|
return href;
|
||||||
}
|
}
|
||||||
@@ -21,7 +18,7 @@ describe('resolveLinks', function() {
|
|||||||
describe('Absolute path', function() {
|
describe('Absolute path', function() {
|
||||||
var TEST = '<p>This is a <a href="/test/cool.md"></a></p>';
|
var TEST = '<p>This is a <a href="/test/cool.md"></a></p>';
|
||||||
|
|
||||||
pit('should resolve path starting by "/" in root directory', function() {
|
it('should resolve path starting by "/" in root directory', function() {
|
||||||
var $ = cheerio.load(TEST);
|
var $ = cheerio.load(TEST);
|
||||||
|
|
||||||
return resolveLinks('hello.md', resolveFileBasic, $)
|
return resolveLinks('hello.md', resolveFileBasic, $)
|
||||||
@@ -31,7 +28,7 @@ describe('resolveLinks', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should resolve path starting by "/" in child directory', function() {
|
it('should resolve path starting by "/" in child directory', function() {
|
||||||
var $ = cheerio.load(TEST);
|
var $ = cheerio.load(TEST);
|
||||||
|
|
||||||
return resolveLinks('afolder/hello.md', resolveFileBasic, $)
|
return resolveLinks('afolder/hello.md', resolveFileBasic, $)
|
||||||
@@ -45,7 +42,7 @@ describe('resolveLinks', function() {
|
|||||||
describe('Custom Resolver', function() {
|
describe('Custom Resolver', function() {
|
||||||
var TEST = '<p>This is a <a href="/test/cool.md"></a> <a href="afile.png"></a></p>';
|
var TEST = '<p>This is a <a href="/test/cool.md"></a> <a href="afile.png"></a></p>';
|
||||||
|
|
||||||
pit('should resolve path correctly for absolute path', function() {
|
it('should resolve path correctly for absolute path', function() {
|
||||||
var $ = cheerio.load(TEST);
|
var $ = cheerio.load(TEST);
|
||||||
|
|
||||||
return resolveLinks('hello.md', resolveFileCustom, $)
|
return resolveLinks('hello.md', resolveFileCustom, $)
|
||||||
@@ -55,7 +52,7 @@ describe('resolveLinks', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should resolve path correctly for absolute path (2)', function() {
|
it('should resolve path correctly for absolute path (2)', function() {
|
||||||
var $ = cheerio.load(TEST);
|
var $ = cheerio.load(TEST);
|
||||||
|
|
||||||
return resolveLinks('afodler/hello.md', resolveFileCustom, $)
|
return resolveLinks('afodler/hello.md', resolveFileCustom, $)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ describe('svgToImg', function() {
|
|||||||
dir = tmp.dirSync();
|
dir = tmp.dirSync();
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should write svg as a file', function() {
|
it('should write svg as a file', function() {
|
||||||
var $ = cheerio.load('<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100" version="1.1"><rect width="200" height="100" stroke="black" stroke-width="6" fill="green"/></svg>');
|
var $ = cheerio.load('<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100" version="1.1"><rect width="200" height="100" stroke="black" stroke-width="6" fill="green"/></svg>');
|
||||||
|
|
||||||
return svgToImg(dir.name, 'index.html', $)
|
return svgToImg(dir.name, 'index.html', $)
|
||||||
|
|||||||
@@ -2,16 +2,17 @@ var cheerio = require('cheerio');
|
|||||||
var tmp = require('tmp');
|
var tmp = require('tmp');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
|
||||||
|
var svgToImg = require('../svgToImg');
|
||||||
|
var svgToPng = require('../svgToPng');
|
||||||
|
|
||||||
describe('svgToPng', function() {
|
describe('svgToPng', function() {
|
||||||
var dir;
|
var dir;
|
||||||
var svgToImg = require('../svgToImg');
|
|
||||||
var svgToPng = require('../svgToPng');
|
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
dir = tmp.dirSync();
|
dir = tmp.dirSync();
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should write svg as png file', function() {
|
it('should write svg as png file', function() {
|
||||||
var $ = cheerio.load('<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100" version="1.1"><rect width="200" height="100" stroke="black" stroke-width="6" fill="green"/></svg>');
|
var $ = cheerio.load('<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100" version="1.1"><rect width="200" height="100" stroke="black" stroke-width="6" fill="green"/></svg>');
|
||||||
var fileName = 'index.html';
|
var fileName = 'index.html';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
var Parse = require('../parse');
|
var Parse = require('../parse');
|
||||||
|
var Promise = require('../utils/promise');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
List and prepare all pages
|
List and prepare all pages
|
||||||
@@ -10,6 +11,10 @@ function preparePages(output) {
|
|||||||
var book = output.getBook();
|
var book = output.getBook();
|
||||||
var logger = book.getLogger();
|
var logger = book.getLogger();
|
||||||
|
|
||||||
|
if (book.isMultilingual()) {
|
||||||
|
return Promise(output);
|
||||||
|
}
|
||||||
|
|
||||||
return Parse.parsePagesList(book)
|
return Parse.parsePagesList(book)
|
||||||
.then(function(pages) {
|
.then(function(pages) {
|
||||||
logger.info.ln('found', pages.size, 'pages');
|
logger.info.ln('found', pages.size, 'pages');
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ var nunjucks = require('nunjucks');
|
|||||||
var DoExtension = require('nunjucks-do')(nunjucks);
|
var DoExtension = require('nunjucks-do')(nunjucks);
|
||||||
|
|
||||||
var Api = require('../../api');
|
var Api = require('../../api');
|
||||||
|
var deprecate = require('../../api/deprecate');
|
||||||
var JSONUtils = require('../../json');
|
var JSONUtils = require('../../json');
|
||||||
var LocationUtils = require('../../utils/location');
|
var LocationUtils = require('../../utils/location');
|
||||||
var fs = require('../../utils/fs');
|
var fs = require('../../utils/fs');
|
||||||
@@ -51,24 +52,58 @@ function createTemplateEngine(output, currentFile) {
|
|||||||
// Create API context
|
// Create API context
|
||||||
var context = Api.encodeGlobal(output);
|
var context = Api.encodeGlobal(output);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Check if a file exists
|
||||||
|
|
||||||
|
@param {String} fileName
|
||||||
|
@return {Boolean}
|
||||||
|
*/
|
||||||
|
function fileExists(fileName) {
|
||||||
|
if (!fileName) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var filePath = PathUtils.resolveInRoot(outputFolder, fileName);
|
||||||
|
return fs.existsSync(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return an article by its path
|
||||||
|
|
||||||
|
@param {String} filePath
|
||||||
|
@return {Object|undefined}
|
||||||
|
*/
|
||||||
|
function getArticleByPath(filePath) {
|
||||||
|
var article = summary.getByPath(filePath);
|
||||||
|
if (!article) return undefined;
|
||||||
|
|
||||||
|
return JSONUtils.encodeSummaryArticle(article);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return a page by its path
|
||||||
|
|
||||||
|
@param {String} filePath
|
||||||
|
@return {Object|undefined}
|
||||||
|
*/
|
||||||
|
function getPageByPath(filePath) {
|
||||||
|
var page = output.getPage(filePath);
|
||||||
|
if (!page) return undefined;
|
||||||
|
|
||||||
|
return JSONUtils.encodePage(page, summary);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return TemplateEngine.create({
|
return TemplateEngine.create({
|
||||||
loader: loader,
|
loader: loader,
|
||||||
|
|
||||||
context: context,
|
context: context,
|
||||||
|
|
||||||
globals: {
|
globals: {
|
||||||
/**
|
getArticleByPath: getArticleByPath,
|
||||||
Return an article by its path
|
getPageByPath: getPageByPath,
|
||||||
|
fileExists: fileExists
|
||||||
@param {String} articlePath
|
|
||||||
@return {Object|undefined}
|
|
||||||
*/
|
|
||||||
getArticleByPath: function(articlePath) {
|
|
||||||
var article = summary.getByPath(articlePath);
|
|
||||||
if (!article) return undefined;
|
|
||||||
|
|
||||||
return JSONUtils.encodeSummaryArticle(article);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
filters: defaultFilters.merge({
|
filters: defaultFilters.merge({
|
||||||
@@ -102,13 +137,9 @@ function createTemplateEngine(output, currentFile) {
|
|||||||
return LocationUtils.normalize(filePath);
|
return LocationUtils.normalize(filePath);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
Check if a file exists
|
fileExists: deprecate.method(book, 'fileExists', fileExists, 'Filter "fileExists" is deprecated, use "fileExists(filename)" '),
|
||||||
*/
|
getArticleByPath: deprecate.method(book, 'getArticleByPath', fileExists, 'Filter "getArticleByPath" is deprecated, use "getArticleByPath(filename)" '),
|
||||||
fileExists: function(fileName) {
|
|
||||||
var filePath = PathUtils.resolveInRoot(outputFolder, fileName);
|
|
||||||
return fs.existsSync(filePath);
|
|
||||||
},
|
|
||||||
|
|
||||||
contentURL: function(filePath) {
|
contentURL: function(filePath) {
|
||||||
return fileToURL(output, filePath);
|
return fileToURL(output, filePath);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ var listAssets = require('../listAssets');
|
|||||||
var parseGlossary = require('../parseGlossary');
|
var parseGlossary = require('../parseGlossary');
|
||||||
|
|
||||||
describe('listAssets', function() {
|
describe('listAssets', function() {
|
||||||
pit('should not list glossary as asset', function() {
|
it('should not list glossary as asset', function() {
|
||||||
var fs = createMockFS({
|
var fs = createMockFS({
|
||||||
'GLOSSARY.md': '# Glossary\n\n## Hello\nDescription for hello',
|
'GLOSSARY.md': '# Glossary\n\n## Hello\nDescription for hello',
|
||||||
'assetFile.js': '',
|
'assetFile.js': '',
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ var createMockFS = require('../../fs/mock');
|
|||||||
describe('parseBook', function() {
|
describe('parseBook', function() {
|
||||||
var parseBook = require('../parseBook');
|
var parseBook = require('../parseBook');
|
||||||
|
|
||||||
pit('should parse multilingual book', function() {
|
it('should parse multilingual book', function() {
|
||||||
var fs = createMockFS({
|
var fs = createMockFS({
|
||||||
'LANGS.md': '# Languages\n\n* [en](en)\n* [fr](fr)',
|
'LANGS.md': '# Languages\n\n* [en](en)\n* [fr](fr)',
|
||||||
'en': {
|
'en': {
|
||||||
@@ -27,7 +27,42 @@ describe('parseBook', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should parse book in a directory', function() {
|
it('should extend configuration for multilingual book', function() {
|
||||||
|
var fs = createMockFS({
|
||||||
|
'LANGS.md': '# Languages\n\n* [en](en)\n* [fr](fr)',
|
||||||
|
'book.json': '{ "title": "Test", "author": "GitBook" }',
|
||||||
|
'en': {
|
||||||
|
'README.md': 'Hello',
|
||||||
|
'book.json': '{ "title": "Test EN" }'
|
||||||
|
},
|
||||||
|
'fr': {
|
||||||
|
'README.md': 'Bonjour'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var book = Book.createForFS(fs);
|
||||||
|
|
||||||
|
return parseBook(book)
|
||||||
|
.then(function(resultBook) {
|
||||||
|
var books = resultBook.getBooks();
|
||||||
|
|
||||||
|
expect(resultBook.isMultilingual()).toBe(true);
|
||||||
|
expect(books.size).toBe(2);
|
||||||
|
|
||||||
|
var en = books.get('en');
|
||||||
|
var fr = books.get('fr');
|
||||||
|
|
||||||
|
var enConfig = en.getConfig();
|
||||||
|
var frConfig = fr.getConfig();
|
||||||
|
|
||||||
|
expect(enConfig.getValue('title')).toBe('Test EN');
|
||||||
|
expect(enConfig.getValue('author')).toBe('GitBook');
|
||||||
|
|
||||||
|
expect(frConfig.getValue('title')).toBe('Test');
|
||||||
|
expect(frConfig.getValue('author')).toBe('GitBook');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse book in a directory', function() {
|
||||||
var fs = createMockFS({
|
var fs = createMockFS({
|
||||||
'book.json': JSON.stringify({
|
'book.json': JSON.stringify({
|
||||||
root: './test'
|
root: './test'
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ var createMockFS = require('../../fs/mock');
|
|||||||
describe('parseGlossary', function() {
|
describe('parseGlossary', function() {
|
||||||
var parseGlossary = require('../parseGlossary');
|
var parseGlossary = require('../parseGlossary');
|
||||||
|
|
||||||
pit('should parse glossary if exists', function() {
|
it('should parse glossary if exists', function() {
|
||||||
var fs = createMockFS({
|
var fs = createMockFS({
|
||||||
'GLOSSARY.md': '# Glossary\n\n## Hello\nDescription for hello'
|
'GLOSSARY.md': '# Glossary\n\n## Hello\nDescription for hello'
|
||||||
});
|
});
|
||||||
@@ -21,7 +21,7 @@ describe('parseGlossary', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should not fail if doesn\'t exist', function() {
|
it('should not fail if doesn\'t exist', function() {
|
||||||
var fs = createMockFS({});
|
var fs = createMockFS({});
|
||||||
var book = Book.createForFS(fs);
|
var book = Book.createForFS(fs);
|
||||||
|
|
||||||
|
|||||||
@@ -17,21 +17,21 @@ describe('parseIgnore', function() {
|
|||||||
return parseIgnore(book);
|
return parseIgnore(book);
|
||||||
}
|
}
|
||||||
|
|
||||||
pit('should load rules from .ignore', function() {
|
it('should load rules from .ignore', function() {
|
||||||
return getBook()
|
return getBook()
|
||||||
.then(function(book) {
|
.then(function(book) {
|
||||||
expect(book.isFileIgnored('test-1.js')).toBeTruthy();
|
expect(book.isFileIgnored('test-1.js')).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should load rules from .gitignore', function() {
|
it('should load rules from .gitignore', function() {
|
||||||
return getBook()
|
return getBook()
|
||||||
.then(function(book) {
|
.then(function(book) {
|
||||||
expect(book.isFileIgnored('test-2.js')).toBeTruthy();
|
expect(book.isFileIgnored('test-2.js')).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should load rules from .bookignore', function() {
|
it('should load rules from .bookignore', function() {
|
||||||
return getBook()
|
return getBook()
|
||||||
.then(function(book) {
|
.then(function(book) {
|
||||||
expect(book.isFileIgnored('test-3.js')).toBeFalsy();
|
expect(book.isFileIgnored('test-3.js')).toBeFalsy();
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ var createMockFS = require('../../fs/mock');
|
|||||||
describe('parseReadme', function() {
|
describe('parseReadme', function() {
|
||||||
var parseReadme = require('../parseReadme');
|
var parseReadme = require('../parseReadme');
|
||||||
|
|
||||||
pit('should parse summary if exists', function() {
|
it('should parse summary if exists', function() {
|
||||||
var fs = createMockFS({
|
var fs = createMockFS({
|
||||||
'README.md': '# Hello\n\nAnd here is the description.'
|
'README.md': '# Hello\n\nAnd here is the description.'
|
||||||
});
|
});
|
||||||
@@ -22,7 +22,7 @@ describe('parseReadme', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should fail if doesn\'t exist', function() {
|
it('should fail if doesn\'t exist', function() {
|
||||||
var fs = createMockFS({});
|
var fs = createMockFS({});
|
||||||
var book = Book.createForFS(fs);
|
var book = Book.createForFS(fs);
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ var createMockFS = require('../../fs/mock');
|
|||||||
describe('parseSummary', function() {
|
describe('parseSummary', function() {
|
||||||
var parseSummary = require('../parseSummary');
|
var parseSummary = require('../parseSummary');
|
||||||
|
|
||||||
pit('should parse summary if exists', function() {
|
it('should parse summary if exists', function() {
|
||||||
var fs = createMockFS({
|
var fs = createMockFS({
|
||||||
'SUMMARY.md': '# Summary\n\n* [Hello](hello.md)'
|
'SUMMARY.md': '# Summary\n\n* [Hello](hello.md)'
|
||||||
});
|
});
|
||||||
@@ -19,7 +19,7 @@ describe('parseSummary', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should not fail if doesn\'t exist', function() {
|
it('should not fail if doesn\'t exist', function() {
|
||||||
var fs = createMockFS({});
|
var fs = createMockFS({});
|
||||||
var book = Book.createForFS(fs);
|
var book = Book.createForFS(fs);
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ var parsers = require('../parsers');
|
|||||||
|
|
||||||
@param {Book} book
|
@param {Book} book
|
||||||
@param {String} filename
|
@param {String} filename
|
||||||
@return {Promise<>}
|
@return {Promise<File | Undefined>}
|
||||||
*/
|
*/
|
||||||
function findParsableFile(book, filename) {
|
function findParsableFile(book, filename) {
|
||||||
var fs = book.getContentFS();
|
var fs = book.getContentFS();
|
||||||
|
|||||||
+11
-10
@@ -1,13 +1,14 @@
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
parseBook: require('./parseBook'),
|
parseBook: require('./parseBook'),
|
||||||
parseSummary: require('./parseSummary'),
|
parseSummary: require('./parseSummary'),
|
||||||
parseGlossary: require('./parseGlossary'),
|
parseGlossary: require('./parseGlossary'),
|
||||||
parseReadme: require('./parseReadme'),
|
parseReadme: require('./parseReadme'),
|
||||||
parseConfig: require('./parseConfig'),
|
parseConfig: require('./parseConfig'),
|
||||||
parsePagesList: require('./parsePagesList'),
|
parsePagesList: require('./parsePagesList'),
|
||||||
parseIgnore: require('./parseIgnore'),
|
parseIgnore: require('./parseIgnore'),
|
||||||
listAssets: require('./listAssets'),
|
listAssets: require('./listAssets'),
|
||||||
parseLanguages: require('./parseLanguages'),
|
parseLanguages: require('./parseLanguages'),
|
||||||
parsePage: require('./parsePage')
|
parsePage: require('./parsePage'),
|
||||||
|
lookupStructureFile: require('./lookupStructureFile')
|
||||||
};
|
};
|
||||||
|
|||||||
+15
-12
@@ -20,20 +20,23 @@ function listAssets(book, pages) {
|
|||||||
var langs = book.getLanguages();
|
var langs = book.getLanguages();
|
||||||
var langsFile = langs.getFile().getPath();
|
var langsFile = langs.getFile().getPath();
|
||||||
|
|
||||||
|
var config = book.getConfig();
|
||||||
|
var configFile = config.getFile().getPath();
|
||||||
|
|
||||||
|
function filterFile(file) {
|
||||||
|
return !(
|
||||||
|
file === summaryFile ||
|
||||||
|
file === glossaryFile ||
|
||||||
|
file === langsFile ||
|
||||||
|
file === configFile ||
|
||||||
|
book.isContentFileIgnored(file) ||
|
||||||
|
pages.has(file)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return timing.measure(
|
return timing.measure(
|
||||||
'parse.listAssets',
|
'parse.listAssets',
|
||||||
fs.listAllFiles()
|
fs.listAllFiles('.', filterFile)
|
||||||
.then(function(files) {
|
|
||||||
return files.filterNot(function(file) {
|
|
||||||
return (
|
|
||||||
book.isContentFileIgnored(file) ||
|
|
||||||
pages.has(file) ||
|
|
||||||
file === summaryFile ||
|
|
||||||
file === glossaryFile ||
|
|
||||||
file === langsFile
|
|
||||||
);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
var findParsableFile = require('./findParsableFile');
|
||||||
|
|
||||||
|
/**
|
||||||
|
Lookup a structure file (ex: SUMMARY.md, GLOSSARY.md) in a book. Uses
|
||||||
|
book's config to find it.
|
||||||
|
|
||||||
|
@param {Book} book
|
||||||
|
@param {String} type: one of ["glossary", "readme", "summary", "langs"]
|
||||||
|
@return {Promise<File>} The path of the file found, relative
|
||||||
|
to the book content root.
|
||||||
|
*/
|
||||||
|
function lookupStructureFile(book, type) {
|
||||||
|
var config = book.getConfig();
|
||||||
|
|
||||||
|
var fileToSearch = config.getValue(['structure', type]);
|
||||||
|
|
||||||
|
return findParsableFile(book, fileToSearch);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = lookupStructureFile;
|
||||||
@@ -42,7 +42,7 @@ function parseMultilingualBook(book) {
|
|||||||
.then(parseBookContent)
|
.then(parseBookContent)
|
||||||
.then(function(result) {
|
.then(function(result) {
|
||||||
// Ignore content of this book when generating parent book
|
// Ignore content of this book when generating parent book
|
||||||
ignore.add(langID + '/**');
|
ignore = ignore.add(langID + '/**');
|
||||||
currentBook = currentBook.set('ignore', ignore);
|
currentBook = currentBook.set('ignore', ignore);
|
||||||
|
|
||||||
return currentBook.addLanguageBook(langID, result);
|
return currentBook.addLanguageBook(langID, result);
|
||||||
|
|||||||
+19
-15
@@ -1,7 +1,5 @@
|
|||||||
var Promise = require('../utils/promise');
|
var Promise = require('../utils/promise');
|
||||||
var Config = require('../models/config');
|
|
||||||
|
|
||||||
var File = require('../models/file');
|
|
||||||
var validateConfig = require('./validateConfig');
|
var validateConfig = require('./validateConfig');
|
||||||
var CONFIG_FILES = require('../constants/configFiles');
|
var CONFIG_FILES = require('../constants/configFiles');
|
||||||
|
|
||||||
@@ -13,6 +11,7 @@ var CONFIG_FILES = require('../constants/configFiles');
|
|||||||
*/
|
*/
|
||||||
function parseConfig(book) {
|
function parseConfig(book) {
|
||||||
var fs = book.getFS();
|
var fs = book.getFS();
|
||||||
|
var config = book.getConfig();
|
||||||
|
|
||||||
return Promise.some(CONFIG_FILES, function(filename) {
|
return Promise.some(CONFIG_FILES, function(filename) {
|
||||||
// Is this file ignored?
|
// Is this file ignored?
|
||||||
@@ -21,15 +20,15 @@ function parseConfig(book) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try loading it
|
// Try loading it
|
||||||
return Promise.all([
|
return fs.loadAsObject(filename)
|
||||||
fs.loadAsObject(filename),
|
.then(function(cfg) {
|
||||||
fs.statFile(filename)
|
return fs.statFile(filename)
|
||||||
])
|
.then(function(file) {
|
||||||
.spread(function(cfg, file) {
|
return {
|
||||||
return {
|
file: file,
|
||||||
file: file,
|
values: cfg
|
||||||
values: cfg
|
};
|
||||||
};
|
});
|
||||||
})
|
})
|
||||||
.fail(function(err) {
|
.fail(function(err) {
|
||||||
if (err.code != 'MODULE_NOT_FOUND') throw(err);
|
if (err.code != 'MODULE_NOT_FOUND') throw(err);
|
||||||
@@ -38,13 +37,18 @@ function parseConfig(book) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
.then(function(result) {
|
.then(function(result) {
|
||||||
var file = result? result.file : File();
|
|
||||||
var values = result? result.values : {};
|
var values = result? result.values : {};
|
||||||
|
|
||||||
values = validateConfig(values);
|
values = validateConfig(values);
|
||||||
|
|
||||||
var config = Config.create(file, values);
|
// Set the file
|
||||||
return book.set('config', config);
|
if (result.file) {
|
||||||
|
config = config.setFile(result.file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge with old values
|
||||||
|
config = config.mergeValues(values);
|
||||||
|
|
||||||
|
return book.setConfig(config);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+22
-18
@@ -1,6 +1,23 @@
|
|||||||
var Promise = require('../utils/promise');
|
var Promise = require('../utils/promise');
|
||||||
var IGNORE_FILES = require('../constants/ignoreFiles');
|
var IGNORE_FILES = require('../constants/ignoreFiles');
|
||||||
|
|
||||||
|
var DEFAULT_IGNORES = [
|
||||||
|
// Skip Git stuff
|
||||||
|
'.git/',
|
||||||
|
|
||||||
|
// Skip OS X meta data
|
||||||
|
'.DS_Store',
|
||||||
|
|
||||||
|
// Skip stuff installed by plugins
|
||||||
|
'node_modules',
|
||||||
|
|
||||||
|
// Skip book outputs
|
||||||
|
'_book',
|
||||||
|
|
||||||
|
// Ignore files in the templates folder
|
||||||
|
'_layouts'
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Parse ignore files
|
Parse ignore files
|
||||||
|
|
||||||
@@ -15,33 +32,20 @@ function parseIgnore(book) {
|
|||||||
var fs = book.getFS();
|
var fs = book.getFS();
|
||||||
var ignore = book.getIgnore();
|
var ignore = book.getIgnore();
|
||||||
|
|
||||||
ignore.addPattern([
|
ignore = ignore.add(DEFAULT_IGNORES);
|
||||||
// Skip Git stuff
|
|
||||||
'.git/',
|
|
||||||
|
|
||||||
// Skip OS X meta data
|
|
||||||
'.DS_Store',
|
|
||||||
|
|
||||||
// Skip stuff installed by plugins
|
|
||||||
'node_modules',
|
|
||||||
|
|
||||||
// Skip book outputs
|
|
||||||
'_book',
|
|
||||||
|
|
||||||
// Ignore files in the templates folder
|
|
||||||
'_layouts'
|
|
||||||
]);
|
|
||||||
|
|
||||||
return Promise.serie(IGNORE_FILES, function(filename) {
|
return Promise.serie(IGNORE_FILES, function(filename) {
|
||||||
return fs.readAsString(filename)
|
return fs.readAsString(filename)
|
||||||
.then(function(content) {
|
.then(function(content) {
|
||||||
ignore.addPattern(content.toString().split(/\r?\n/));
|
ignore = ignore.add(content.toString().split(/\r?\n/));
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
return Promise();
|
return Promise();
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
.thenResolve(book);
|
.then(function() {
|
||||||
|
return book.setIgnore(ignore);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = parseIgnore;
|
module.exports = parseIgnore;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ var Immutable = require('immutable');
|
|||||||
var timing = require('../utils/timing');
|
var timing = require('../utils/timing');
|
||||||
var Page = require('../models/page');
|
var Page = require('../models/page');
|
||||||
var walkSummary = require('./walkSummary');
|
var walkSummary = require('./walkSummary');
|
||||||
|
var parsePage = require('./parsePage');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Parse all pages from a book as an OrderedMap
|
Parse all pages from a book as an OrderedMap
|
||||||
@@ -27,10 +28,11 @@ function parsePagesList(book) {
|
|||||||
|
|
||||||
return fs.statFile(filepath)
|
return fs.statFile(filepath)
|
||||||
.then(function(file) {
|
.then(function(file) {
|
||||||
map = map.set(
|
var page = Page.createForFile(file);
|
||||||
filepath,
|
return parsePage(book, page);
|
||||||
Page.createForFile(file)
|
})
|
||||||
);
|
.then(function(page) {
|
||||||
|
map = map.set(filepath, page);
|
||||||
}, function() {
|
}, function() {
|
||||||
// file doesn't exist
|
// file doesn't exist
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
var findParsableFile = require('./findParsableFile');
|
|
||||||
var Promise = require('../utils/promise');
|
var Promise = require('../utils/promise');
|
||||||
var error = require('../utils/error');
|
var error = require('../utils/error');
|
||||||
|
var lookupStructureFile = require('./lookupStructureFile');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Parse a ParsableFile using a specific method
|
Parse a ParsableFile using a specific method
|
||||||
@@ -55,11 +55,8 @@ function parseFile(fs, file, type) {
|
|||||||
*/
|
*/
|
||||||
function parseStructureFile(book, type) {
|
function parseStructureFile(book, type) {
|
||||||
var fs = book.getContentFS();
|
var fs = book.getContentFS();
|
||||||
var config = book.getConfig();
|
|
||||||
|
|
||||||
var fileToSearch = config.getValue(['structure', type]);
|
return lookupStructureFile(book, type)
|
||||||
|
|
||||||
return findParsableFile(book, fileToSearch)
|
|
||||||
.then(function(file) {
|
.then(function(file) {
|
||||||
if (!file) return [undefined, undefined];
|
if (!file) return [undefined, undefined];
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ var Immutable = require('immutable');
|
|||||||
describe('findInstalled', function() {
|
describe('findInstalled', function() {
|
||||||
var findInstalled = require('../findInstalled');
|
var findInstalled = require('../findInstalled');
|
||||||
|
|
||||||
pit('must list default plugins for gitbook directory', function() {
|
it('must list default plugins for gitbook directory', function() {
|
||||||
// Read gitbook-plugins from package.json
|
// Read gitbook-plugins from package.json
|
||||||
var pkg = require(path.resolve(__dirname, '../../../package.json'));
|
var pkg = require(path.resolve(__dirname, '../../../package.json'));
|
||||||
var gitbookPlugins = Immutable.Seq(pkg.dependencies)
|
var gitbookPlugins = Immutable.Seq(pkg.dependencies)
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
jest.autoMockOff();
|
|
||||||
|
|
||||||
var Promise = require('../../utils/promise');
|
var Promise = require('../../utils/promise');
|
||||||
var Plugin = require('../../models/plugin');
|
var Plugin = require('../../models/plugin');
|
||||||
|
var validatePlugin = require('../validatePlugin');
|
||||||
|
|
||||||
describe('validatePlugin', function() {
|
describe('validatePlugin', function() {
|
||||||
var validatePlugin = require('../validatePlugin');
|
it('must not validate a not loaded plugin', function() {
|
||||||
|
|
||||||
pit('must not validate a not loaded plugin', function() {
|
|
||||||
var plugin = Plugin.createFromString('test');
|
var plugin = Plugin.createFromString('test');
|
||||||
|
|
||||||
return validatePlugin(plugin)
|
return validatePlugin(plugin)
|
||||||
@@ -17,5 +13,4 @@ describe('validatePlugin', function() {
|
|||||||
return Promise();
|
return Promise();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,34 +1,92 @@
|
|||||||
|
var path = require('path');
|
||||||
|
|
||||||
var TemplateEngine = require('../../models/templateEngine');
|
var TemplateEngine = require('../../models/templateEngine');
|
||||||
var renderTemplate = require('../render');
|
var renderTemplate = require('../render');
|
||||||
|
var ConrefsLoader = require('../conrefsLoader');
|
||||||
|
|
||||||
describe('ConrefsLoader', function() {
|
describe('ConrefsLoader', function() {
|
||||||
var ConrefsLoader = require('../conrefsLoader');
|
var dirName = __dirname + '/';
|
||||||
|
var fileName = path.join(dirName, 'test.md');
|
||||||
var engine = TemplateEngine({
|
|
||||||
loader: new ConrefsLoader(__dirname)
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Git', function() {
|
describe('Git', function() {
|
||||||
pit('should include content from git', function() {
|
var engine = TemplateEngine({
|
||||||
return renderTemplate(engine, 'test.md', '{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md" %}')
|
loader: new ConrefsLoader(dirName)
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should include content from git', function() {
|
||||||
|
return renderTemplate(engine, fileName, '{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md" %}')
|
||||||
.then(function(out) {
|
.then(function(out) {
|
||||||
expect(out.getContent()).toBe('Hello from git');
|
expect(out.getContent()).toBe('Hello from git');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should handle deep inclusion (1)', function() {
|
it('should handle deep inclusion (1)', function() {
|
||||||
return renderTemplate(engine, 'test.md', '{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test2.md" %}')
|
return renderTemplate(engine, fileName, '{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test2.md" %}')
|
||||||
.then(function(out) {
|
.then(function(out) {
|
||||||
expect(out.getContent()).toBe('First Hello. Hello from git');
|
expect(out.getContent()).toBe('First Hello. Hello from git');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should handle deep inclusion (2)', function() {
|
it('should handle deep inclusion (2)', function() {
|
||||||
return renderTemplate(engine, 'test.md', '{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test3.md" %}')
|
return renderTemplate(engine, fileName, '{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test3.md" %}')
|
||||||
.then(function(out) {
|
.then(function(out) {
|
||||||
expect(out.getContent()).toBe('First Hello. Hello from git');
|
expect(out.getContent()).toBe('First Hello. Hello from git');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Local', function() {
|
||||||
|
var engine = TemplateEngine({
|
||||||
|
loader: new ConrefsLoader(dirName)
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Relative', function() {
|
||||||
|
it('should resolve basic relative filepath', function() {
|
||||||
|
return renderTemplate(engine, fileName, '{% include "include.md" %}')
|
||||||
|
.then(function(out) {
|
||||||
|
expect(out.getContent()).toBe('Hello World');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should resolve basic parent filepath', function() {
|
||||||
|
return renderTemplate(engine, path.join(dirName, 'hello/test.md'), '{% include "../include.md" %}')
|
||||||
|
.then(function(out) {
|
||||||
|
expect(out.getContent()).toBe('Hello World');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Absolute', function() {
|
||||||
|
it('should resolve absolute filepath', function() {
|
||||||
|
return renderTemplate(engine, fileName, '{% include "/include.md" %}')
|
||||||
|
.then(function(out) {
|
||||||
|
expect(out.getContent()).toBe('Hello World');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should resolve absolute filepath when in a directory', function() {
|
||||||
|
return renderTemplate(engine, path.join(dirName, 'hello/test.md'), '{% include "/include.md" %}')
|
||||||
|
.then(function(out) {
|
||||||
|
expect(out.getContent()).toBe('Hello World');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('transform', function() {
|
||||||
|
function transform(filePath, source) {
|
||||||
|
return 'test-' + source + '-endtest';
|
||||||
|
}
|
||||||
|
var engine = TemplateEngine({
|
||||||
|
loader: new ConrefsLoader(dirName, transform)
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should transform included content', function() {
|
||||||
|
return renderTemplate(engine, fileName, '{% include "include.md" %}')
|
||||||
|
.then(function(out) {
|
||||||
|
expect(out.getContent()).toBe('test-Hello World-endtest');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
Hello World
|
||||||
@@ -1,27 +1,26 @@
|
|||||||
var TemplateEngine = require('../../models/templateEngine');
|
var Immutable = require('immutable');
|
||||||
|
|
||||||
var TemplateBlock = require('../../models/templateBlock');
|
var TemplateBlock = require('../../models/templateBlock');
|
||||||
var replaceShortcuts = require('../replaceShortcuts');
|
var replaceShortcuts = require('../replaceShortcuts');
|
||||||
|
|
||||||
describe('replaceShortcuts', function() {
|
describe('replaceShortcuts', function() {
|
||||||
var engine = TemplateEngine.create({
|
var blocks = Immutable.List([
|
||||||
blocks:[
|
TemplateBlock.create('math', {
|
||||||
TemplateBlock.create('math', {
|
shortcuts: {
|
||||||
shortcuts: {
|
start: '$$',
|
||||||
start: '$$',
|
end: '$$',
|
||||||
end: '$$',
|
parsers: ['markdown']
|
||||||
parsers: ['markdown']
|
}
|
||||||
}
|
})
|
||||||
})
|
]);
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should correctly replace inline matches by block', function() {
|
it('should correctly replace inline matches by block', function() {
|
||||||
var content = replaceShortcuts(engine, 'test.md', 'Hello $$a = b$$');
|
var content = replaceShortcuts(blocks, 'test.md', 'Hello $$a = b$$');
|
||||||
expect(content).toBe('Hello {% math %}a = b{% endmath %}');
|
expect(content).toBe('Hello {% math %}a = b{% endmath %}');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly replace block matches', function() {
|
it('should correctly replace block matches', function() {
|
||||||
var content = replaceShortcuts(engine, 'test.md', 'Hello\n$$\na = b\n$$\n');
|
var content = replaceShortcuts(blocks, 'test.md', 'Hello\n$$\na = b\n$$\n');
|
||||||
expect(content).toBe('Hello\n{% math %}\na = b\n{% endmath %}\n');
|
expect(content).toBe('Hello\n{% math %}\na = b\n{% endmath %}\n');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,12 +12,18 @@ var PathUtils = require('../utils/path');
|
|||||||
- relative url ("./test.md")
|
- relative url ("./test.md")
|
||||||
- absolute url ("/test.md")
|
- absolute url ("/test.md")
|
||||||
- git url ("")
|
- git url ("")
|
||||||
|
|
||||||
|
|
||||||
|
@param {String} rootFolder
|
||||||
|
@param {Function(filePath, source)} transformFn (optional)
|
||||||
|
@param {Logger} logger (optional)
|
||||||
*/
|
*/
|
||||||
var ConrefsLoader = nunjucks.Loader.extend({
|
var ConrefsLoader = nunjucks.Loader.extend({
|
||||||
async: true,
|
async: true,
|
||||||
|
|
||||||
init: function(rootFolder, logger) {
|
init: function(rootFolder, transformFn, logger) {
|
||||||
this.rootFolder = rootFolder;
|
this.rootFolder = rootFolder;
|
||||||
|
this.transformFn = transformFn;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.git = new Git();
|
this.git = new Git();
|
||||||
},
|
},
|
||||||
@@ -34,8 +40,15 @@ var ConrefsLoader = nunjucks.Loader.extend({
|
|||||||
if (that.logger) that.logger.debug.ln('resolve from git', sourceURL, 'to', filepath);
|
if (that.logger) that.logger.debug.ln('resolve from git', sourceURL, 'to', filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read file from absolute path
|
// Read file from absolute path
|
||||||
return fs.readFile(filepath)
|
return fs.readFile(filepath)
|
||||||
|
.then(function(source) {
|
||||||
|
if (that.transformFn) {
|
||||||
|
return that.transformFn(filepath, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
return source;
|
||||||
|
})
|
||||||
.then(function(source) {
|
.then(function(source) {
|
||||||
return {
|
return {
|
||||||
src: source.toString('utf8'),
|
src: source.toString('utf8'),
|
||||||
@@ -49,7 +62,14 @@ var ConrefsLoader = nunjucks.Loader.extend({
|
|||||||
resolve: function(from, to) {
|
resolve: function(from, to) {
|
||||||
// If origin is in the book, we enforce result file to be in the book
|
// If origin is in the book, we enforce result file to be in the book
|
||||||
if (PathUtils.isInRoot(this.rootFolder, from)) {
|
if (PathUtils.isInRoot(this.rootFolder, from)) {
|
||||||
var href = LocationUtils.toAbsolute(to, path.dirname(from), '');
|
|
||||||
|
// Path of current template in the rootFolder (not absolute to fs)
|
||||||
|
var fromRelative = path.relative(this.rootFolder, from);
|
||||||
|
|
||||||
|
// Resolve "to" to a filepath relative to rootFolder
|
||||||
|
var href = LocationUtils.toAbsolute(to, path.dirname(fromRelative), '');
|
||||||
|
|
||||||
|
// Return absolute path
|
||||||
return PathUtils.resolveInRoot(this.rootFolder, href);
|
return PathUtils.resolveInRoot(this.rootFolder, href);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
render: require('./render'),
|
render: require('./render'),
|
||||||
renderFile: require('./renderFile'),
|
renderFile: require('./renderFile'),
|
||||||
postRender: require('./postRender'),
|
postRender: require('./postRender'),
|
||||||
|
replaceShortcuts: require('./replaceShortcuts'),
|
||||||
|
|
||||||
ConrefsLoader: require('./conrefsLoader'),
|
ConrefsLoader: require('./conrefsLoader'),
|
||||||
ThemesLoader: require('./themesLoader')
|
ThemesLoader: require('./themesLoader')
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,12 +5,11 @@ var parsers = require('../parsers');
|
|||||||
Return a list of all shortcuts that can apply
|
Return a list of all shortcuts that can apply
|
||||||
to a file for a TemplatEngine
|
to a file for a TemplatEngine
|
||||||
|
|
||||||
@param {TemplateEngine} engine
|
@param {List<TemplateBlock>} engine
|
||||||
@param {String} filePath
|
@param {String} filePath
|
||||||
@return {List<TemplateShortcut>}
|
@return {List<TemplateShortcut>}
|
||||||
*/
|
*/
|
||||||
function listShortcuts(engine, filePath) {
|
function listShortcuts(blocks, filePath) {
|
||||||
var blocks = engine.getBlocks();
|
|
||||||
var parser = parsers.getForFile(filePath);
|
var parser = parsers.getForFile(filePath);
|
||||||
|
|
||||||
if (!parser) {
|
if (!parser) {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ function postRender(engine, output) {
|
|||||||
var content = output.getContent();
|
var content = output.getContent();
|
||||||
var blocks = output.getBlocks();
|
var blocks = output.getBlocks();
|
||||||
|
|
||||||
var result = replaceBlocks(content);
|
var result = replaceBlocks(content, blocks);
|
||||||
|
|
||||||
return Promise.forEach(blocks, function(block) {
|
return Promise.forEach(blocks, function(block) {
|
||||||
var post = block.get('post');
|
var post = block.get('post');
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ var replaceShortcuts = require('./replaceShortcuts');
|
|||||||
Render a template
|
Render a template
|
||||||
|
|
||||||
@param {TemplateEngine} engine
|
@param {TemplateEngine} engine
|
||||||
@param {String} filePath
|
@param {String} filePath: absolute path for the loader
|
||||||
@param {String} content
|
@param {String} content
|
||||||
@param {Object} context
|
@param {Object} context
|
||||||
@return {Promise<TemplateOutput>}
|
@return {Promise<TemplateOutput>}
|
||||||
@@ -22,7 +22,7 @@ function renderTemplate(engine, filePath, content, context) {
|
|||||||
var env = engine.toNunjucks(blocks);
|
var env = engine.toNunjucks(blocks);
|
||||||
|
|
||||||
// Replace shortcuts from plugin's blocks
|
// Replace shortcuts from plugin's blocks
|
||||||
content = replaceShortcuts(engine, filePath, content);
|
content = replaceShortcuts(engine.getBlocks(), filePath, content);
|
||||||
|
|
||||||
return timing.measure(
|
return timing.measure(
|
||||||
'template.render',
|
'template.render',
|
||||||
|
|||||||
@@ -13,14 +13,17 @@ var render = require('./render');
|
|||||||
function renderTemplateFile(engine, filePath, context) {
|
function renderTemplateFile(engine, filePath, context) {
|
||||||
var loader = engine.getLoader();
|
var loader = engine.getLoader();
|
||||||
|
|
||||||
|
// Resolve the filePath
|
||||||
|
var resolvedFilePath = loader.resolve(null, filePath);
|
||||||
|
|
||||||
return Promise()
|
return Promise()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
if (!loader.async) {
|
if (!loader.async) {
|
||||||
return loader.getSource(filePath);
|
return loader.getSource(resolvedFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
var deferred = Promise.defer();
|
var deferred = Promise.defer();
|
||||||
loader.getSource(filePath, deferred.makeNodeResolver());
|
loader.getSource(resolvedFilePath, deferred.makeNodeResolver());
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
})
|
})
|
||||||
.then(function(result) {
|
.then(function(result) {
|
||||||
|
|||||||
@@ -26,13 +26,13 @@ function applyShortcut(content, shortcut) {
|
|||||||
/**
|
/**
|
||||||
Replace shortcuts from blocks in a string
|
Replace shortcuts from blocks in a string
|
||||||
|
|
||||||
@param {TemplateEngine} engine
|
@param {List<TemplateBlock>} engine
|
||||||
@param {String} filePath
|
@param {String} filePath
|
||||||
@param {String} content
|
@param {String} content
|
||||||
@return {String}
|
@return {String}
|
||||||
*/
|
*/
|
||||||
function replaceShortcuts(engine, filePath, content) {
|
function replaceShortcuts(blocks, filePath, content) {
|
||||||
var shortcuts = listShortcuts(engine, filePath);
|
var shortcuts = listShortcuts(blocks, filePath);
|
||||||
return shortcuts.reduce(applyShortcut, content);
|
return shortcuts.reduce(applyShortcut, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ describe('Git', function() {
|
|||||||
expect(Git.isUrl('git+git@github.com:GitbookIO/gitbook.git/directory/README.md#e1594cde2c32e4ff48f6c4eff3d3d461743d74e1')).toBeTruthy();
|
expect(Git.isUrl('git+git@github.com:GitbookIO/gitbook.git/directory/README.md#e1594cde2c32e4ff48f6c4eff3d3d461743d74e1')).toBeTruthy();
|
||||||
|
|
||||||
// Non valid
|
// Non valid
|
||||||
expect(Git.isUrl('https://github.com/Hello/world.git')).not.toBeTruthy();
|
expect(Git.isUrl('https://github.com/Hello/world.git')).toBeFalsy();
|
||||||
expect(Git.isUrl('README.md')).not.toBeTruthy();
|
expect(Git.isUrl('README.md')).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse HTTPS urls', function() {
|
it('should parse HTTPS urls', function() {
|
||||||
@@ -45,7 +45,7 @@ describe('Git', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Cloning and resolving', function() {
|
describe('Cloning and resolving', function() {
|
||||||
pit('should clone an HTTPS url', function() {
|
it('should clone an HTTPS url', function() {
|
||||||
var git = new Git(path.join(os.tmpdir(), 'test-git-'+Date.now()));
|
var git = new Git(path.join(os.tmpdir(), 'test-git-'+Date.now()));
|
||||||
return git.resolve('git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md')
|
return git.resolve('git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md')
|
||||||
.then(function(filename) {
|
.then(function(filename) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user