Compare commits

...

25 Commits

Author SHA1 Message Date
Samy Pesse 0bce3517fd Bump version to 3.0.2 2016-05-25 21:50:38 +02:00
Samy Pesse 089815a8fd Fix #1328: fix crash when anchor links 2016-05-25 21:49:58 +02:00
Samy Pesse 7e8f1a9632 Bump version to 3.0.1 2016-05-25 20:00:04 +02:00
Samy Pesse 8469648241 Update theme-default@1.0.2 2016-05-25 17:14:15 +02:00
Samy Pessé e7a44358a5 Update Changelog 2016-05-24 15:38:26 +02:00
Samy Pessé fb930d889f Fix anchor breaking links resolution 2016-05-24 15:32:30 +02:00
Samy Pessé 721a75309b Fix #1316: adapt regexp to handle dot in filenames 2016-05-23 13:00:01 +02:00
Samy Pessé b856bff91b Add failing test for #1316 2016-05-23 12:48:46 +02:00
Samy Pesse 0744f000f9 Fix doc for conrefs 2016-05-22 19:59:53 +02:00
Samy Pesse d1e226dba5 Bump version to 3.0.0 2016-05-20 22:18:37 +02:00
Samy Pesse 1923d28d71 Update dependencies 2016-05-20 22:17:44 +02:00
Samy Pessé 484a306adb Fix error with isInRoot when empty root 2016-05-20 21:41:02 +02:00
Samy Pessé 5bfc9f2f56 Fix PathUtils.isInRoot on windows 2016-05-20 21:37:22 +02:00
Samy Pesse 86a65e5287 Improve appveyor configuration 2016-05-20 19:23:51 +02:00
Samy Pesse 956d301dd7 Add node v6 to appveyor matrix 2016-05-20 18:22:44 +02:00
Samy Pesse 00d1a7b5a6 Update theme-default@1.0.1 2016-05-20 18:17:34 +02:00
Samy Pessé 2718c9c017 Fix test command for windows 2016-05-19 10:45:25 +02:00
Samy Pesse 3234c1e03f Fix #1310: enforce language config in language books 2016-05-19 00:15:09 +02:00
Aaron O'Mullan c8f8eece92 Merge pull request #1308 from arebee/patch-1
Fix english phrasing for Node version.
2016-05-19 00:10:08 +02:00
Richard Burte 7394efa9dc Fix english phrasing for Node version. 2016-05-18 09:54:04 -07:00
Samy Pesse 3e4241fc88 Implement renderInline method and missing output methods for API 2016-05-17 19:45:48 +02:00
Samy Pesse a5ae79604c Implement renderBlock method for plugin API 2016-05-17 19:30:28 +02:00
Soreine fc4bdd68a1 Can only use file names 2016-05-17 16:47:52 +02:00
Soreine f83975b022 Mention the structure configuration variable 2016-05-17 16:37:13 +02:00
Soreine 167d3957bf Expose lookup method for parsable files 2016-05-17 12:48:03 +02:00
23 changed files with 270 additions and 63 deletions
+8 -1
View File
@@ -2,7 +2,14 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 3.0.0 (pre)
## 3.0.2
- Fix crash for anchor links
## 3.0.1
- Fix regression in link resolution when contain anchor
- Fix `structure.<name>` configuration not supporting filenames with dots
## 3.0.0
- Summary can contain external links and anchors (Fix [#776](https://github.com/GitbookIO/gitbook/issues/776))
- Summary can contain differents entitled sections
- Glossary is generated as a normal page
+9
View File
@@ -5,13 +5,18 @@ init:
# Test against these versions of Node.js.
environment:
matrix:
- nodejs_version: "6"
- nodejs_version: "5"
- nodejs_version: "4"
matrix:
fast_finish: true
# Install scripts. (runs after repo cloning)
install:
# Get the latest stable version of Node.js or io.js
- ps: Install-Product node $env:nodejs_version
- set CI=true
# install svgexport
- npm install svgexport -g
# install modules
@@ -27,3 +32,7 @@ test_script:
# Don't actually build.
build: off
# Clone only last commit
shallow_clone: true
clone_depth: 1
+13
View File
@@ -7,6 +7,7 @@ GitBook allows you to customize your book using a flexible configuration. These
| Variable | Description |
| -------- | ----------- |
| `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. |
| `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. |
@@ -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 |
### 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 Output can be customized using a set of options in the `book.json`:
+1 -1
View File
@@ -37,7 +37,7 @@ var filepath = output.resolve('myimage.png');
var fileurl = output.toURL('mychapter/README.md');
// Write a file in the output folder
output.write('hello.txt', 'Hello World')
output.writeFile('hello.txt', 'Hello World')
.then(function() { ... });
// Copy a file to the output folder
+1 -1
View File
@@ -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:
* NodeJS (v4.0.0 and above are adviced)
* NodeJS (v4.0.0 and above is recommended)
* Windows, Linux, Unix, or Mac OS X
##### Install with NPM
+1 -1
View File
@@ -51,5 +51,5 @@ This is the default content
# License
{% import "./LICENSE" %}
{% include "./LICENSE" %}
```
+65
View File
@@ -8,6 +8,7 @@ var deprecate = require('./deprecate');
var fileToURL = require('../output/helper/fileToURL');
var defaultBlocks = require('../constants/defaultBlocks');
var gitbook = require('../gitbook');
var parsers = require('../parsers');
var encodeConfig = require('./encodeConfig');
var encodeSummary = require('./encodeSummary');
@@ -95,6 +96,34 @@ function encodeGlobal(output) {
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: {
/**
Apply a templating block and returns its result
@@ -142,6 +171,21 @@ function encodeGlobal(output) {
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,
It creates the required folder
@@ -160,6 +204,27 @@ function encodeGlobal(output) {
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);
});
});
}
},
+5 -1
View File
@@ -11,5 +11,9 @@ module.exports = {
// Modifiers
SummaryModifier: Modifiers.Summary,
ConfigModifier: Modifiers.Config
ConfigModifier: Modifiers.Config,
// Constants
CONFIG_FILES: require('./constants/configFiles.js'),
IGNORE_FILES: require('./constants/ignoreFiles.js')
};
+36
View File
@@ -0,0 +1,36 @@
var jsonschema = require('jsonschema');
var schema = require('../configSchema');
describe('configSchema', function() {
function validate(cfg) {
var v = new jsonschema.Validator();
return v.validate(cfg, schema, {
propertyName: 'config'
});
}
describe('structure', function() {
it('should accept dot in filename', function() {
var result = validate({
structure: {
readme: 'book-intro.adoc'
}
});
expect(result.errors.length).toBe(0);
});
it('should not accept filepath', function() {
var result = validate({
structure: {
readme: 'folder/myFile.md'
}
});
expect(result.errors.length).toBe(1);
});
});
});
+6 -4
View File
@@ -1,3 +1,5 @@
var FILENAME_REGEX = '^[a-z-._\d,\s]+$';
module.exports = {
'$schema': 'http://json-schema.org/schema#',
'id': 'https://gitbook.com/schemas/book.json',
@@ -57,25 +59,25 @@ module.exports = {
'default': 'LANGS.md',
'type': 'string',
'title': 'File to use as languages index',
'pattern': '^[0-9a-zA-Z ... ]+$'
'pattern': FILENAME_REGEX
},
'readme': {
'default': 'README.md',
'type': 'string',
'title': 'File to use as preface',
'pattern': '^[0-9a-zA-Z ... ]+$'
'pattern': FILENAME_REGEX
},
'glossary': {
'default': 'GLOSSARY.md',
'type': 'string',
'title': 'File to use as glossary index',
'pattern': '^[0-9a-zA-Z ... ]+$'
'pattern': FILENAME_REGEX
},
'summary': {
'default': 'SUMMARY.md',
'type': 'string',
'title': 'File to use as table of contents',
'pattern': '^[0-9a-zA-Z ... ]+$'
'pattern': FILENAME_REGEX
}
},
'additionalProperties': false
+6 -2
View File
@@ -324,12 +324,16 @@ Book.prototype.getDefaultGlossaryPath = function() {
*/
Book.createFromParent = function createFromParent(parent, language) {
var ignore = parent.getIgnore();
var config = parent.getConfig();
// Set language in configuration
config = config.setValue('language', language);
return new Book({
// Inherits config. logegr and list of ignored files
logger: parent.getLogger(),
config: parent.getConfig(),
ignore: Ignore().add(ignore),
config: config,
ignore: ignore,
language: language,
fs: FS.reduceScope(parent.getContentFS(), language)
+1 -1
View File
@@ -229,7 +229,7 @@ FS.prototype.listAllFiles = function(dirName, filterFn) {
};
/**
Find a file in a folder (case incensitive)
Find a file in a folder (case insensitive)
Return the found filename
@param {String} dirname
+5
View File
@@ -55,6 +55,11 @@ Parser.prototype.parsePage = function(content) {
return Promise(page(content));
};
Parser.prototype.parseInline = function(content) {
var inline = this.get('inline');
return Promise(inline(content));
};
Parser.prototype.parseLanguages = function(content) {
var langs = this.get('langs');
return Promise(langs(content));
-1
View File
@@ -4,7 +4,6 @@ var Promise = require('../utils/promise');
var error = require('../utils/error');
var timing = require('../utils/timing');
var Parse = require('../parse');
var Templating = require('../templating');
var JSONUtils = require('../json');
var createTemplateEngine = require('./createTemplateEngine');
+27 -3
View File
@@ -4,7 +4,7 @@ var resolveLinks = require('../resolveLinks');
describe('resolveLinks', function() {
function resolveFileBasic(href) {
return href;
return 'fakeDir/' + href;
}
function resolveFileCustom(href) {
@@ -24,7 +24,7 @@ describe('resolveLinks', function() {
return resolveLinks('hello.md', resolveFileBasic, $)
.then(function() {
var link = $('a');
expect(link.attr('href')).toBe('test/cool.md');
expect(link.attr('href')).toBe('fakeDir/test/cool.md');
});
});
@@ -34,7 +34,31 @@ describe('resolveLinks', function() {
return resolveLinks('afolder/hello.md', resolveFileBasic, $)
.then(function() {
var link = $('a');
expect(link.attr('href')).toBe('../test/cool.md');
expect(link.attr('href')).toBe('../fakeDir/test/cool.md');
});
});
});
describe('Anchor', function() {
it('should prevent anchors in resolution', function() {
var TEST = '<p>This is a <a href="test/cool.md#an-anchor"></a></p>';
var $ = cheerio.load(TEST);
return resolveLinks('hello.md', resolveFileCustom, $)
.then(function() {
var link = $('a');
expect(link.attr('href')).toBe('test/cool.html#an-anchor');
});
});
it('should ignore pure anchor links', function() {
var TEST = '<p>This is a <a href="#an-anchor"></a></p>';
var $ = cheerio.load(TEST);
return resolveLinks('hello.md', resolveFileCustom, $)
.then(function() {
var link = $('a');
expect(link.attr('href')).toBe('#an-anchor');
});
});
});
+16 -6
View File
@@ -1,4 +1,5 @@
var path = require('path');
var url = require('url');
var LocationUtils = require('../../utils/location');
var editHTMLElement = require('./editHTMLElement');
@@ -27,14 +28,23 @@ function resolveLinks(currentFile, resolveFile, $) {
return;
}
// Calcul absolute path for this
href = LocationUtils.toAbsolute(href, currentDirectory, '.');
// Split anchor
var parsed = url.parse(href);
href = parsed.pathname || '';
// Resolve file
href = resolveFile(href);
if (href) {
// Calcul absolute path for this
href = LocationUtils.toAbsolute(href, currentDirectory, '.');
// Convert back to relative
href = LocationUtils.relative(currentDirectory, href);
// Resolve file
href = resolveFile(href);
// Convert back to relative
href = LocationUtils.relative(currentDirectory, href);
}
// Add back anchor
href = href + (parsed.hash || '');
$a.attr('href', href);
});
+1 -1
View File
@@ -8,7 +8,7 @@ var parsers = require('../parsers');
@param {Book} book
@param {String} filename
@return {Promise<>}
@return {Promise<File | Undefined>}
*/
function findParsableFile(book, filename) {
var fs = book.getContentFS();
+11 -10
View File
@@ -1,13 +1,14 @@
module.exports = {
parseBook: require('./parseBook'),
parseSummary: require('./parseSummary'),
parseGlossary: require('./parseGlossary'),
parseReadme: require('./parseReadme'),
parseConfig: require('./parseConfig'),
parsePagesList: require('./parsePagesList'),
parseIgnore: require('./parseIgnore'),
listAssets: require('./listAssets'),
parseLanguages: require('./parseLanguages'),
parsePage: require('./parsePage')
parseBook: require('./parseBook'),
parseSummary: require('./parseSummary'),
parseGlossary: require('./parseGlossary'),
parseReadme: require('./parseReadme'),
parseConfig: require('./parseConfig'),
parsePagesList: require('./parsePagesList'),
parseIgnore: require('./parseIgnore'),
listAssets: require('./listAssets'),
parseLanguages: require('./parseLanguages'),
parsePage: require('./parsePage'),
lookupStructureFile: require('./lookupStructureFile')
};
+20
View File
@@ -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;
+18 -16
View File
@@ -1,6 +1,23 @@
var Promise = require('../utils/promise');
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
@@ -15,22 +32,7 @@ function parseIgnore(book) {
var fs = book.getFS();
var ignore = book.getIgnore();
ignore = ignore.add([
// 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'
]);
ignore = ignore.add(DEFAULT_IGNORES);
return Promise.serie(IGNORE_FILES, function(filename) {
return fs.readAsString(filename)
+2 -5
View File
@@ -1,6 +1,6 @@
var findParsableFile = require('./findParsableFile');
var Promise = require('../utils/promise');
var error = require('../utils/error');
var lookupStructureFile = require('./lookupStructureFile');
/**
Parse a ParsableFile using a specific method
@@ -55,11 +55,8 @@ function parseFile(fs, file, type) {
*/
function parseStructureFile(book, type) {
var fs = book.getContentFS();
var config = book.getConfig();
var fileToSearch = config.getValue(['structure', type]);
return findParsableFile(book, fileToSearch)
return lookupStructureFile(book, type)
.then(function(file) {
if (!file) return [undefined, undefined];
+9
View File
@@ -8,7 +8,16 @@ function normalizePath(filename) {
// Return true if file path is inside a folder
function isInRoot(root, filename) {
root = path.normalize(root);
filename = path.normalize(filename);
if (root === '.') {
return true;
}
if (root[root.length - 1] != path.sep) {
root = root + path.sep;
}
return (filename.substr(0, root.length) === root);
}
+9 -9
View File
@@ -1,6 +1,6 @@
{
"name": "gitbook",
"version": "3.0.0-pre.15",
"version": "3.0.2",
"homepage": "https://www.gitbook.com",
"description": "Library and cmd utility to generate GitBooks",
"main": "lib/index.js",
@@ -8,7 +8,7 @@
"dependencies": {
"bash-color": "0.0.4",
"cheerio": "0.20.0",
"chokidar": "1.4.3",
"chokidar": "1.5.0",
"cp": "0.2.0",
"cpr": "1.1.1",
"crc": "3.4.0",
@@ -20,7 +20,7 @@
"escape-string-regexp": "1.0.5",
"extend": "^3.0.0",
"fresh-require": "1.0.3",
"front-matter": "2.0.7",
"front-matter": "2.0.8",
"gitbook-asciidoc": "1.1.4",
"gitbook-markdown": "1.2.3",
"gitbook-plugin-fontsettings": "1.0.3",
@@ -29,20 +29,20 @@
"gitbook-plugin-lunr": "1.1.0",
"gitbook-plugin-search": "2.2.1",
"gitbook-plugin-sharing": "1.0.2",
"gitbook-plugin-theme-default": "1.0.0",
"gitbook-plugin-theme-default": "1.0.2",
"github-slugid": "1.0.1",
"graceful-fs": "4.1.3",
"graceful-fs": "4.1.4",
"i18n-t": "1.0.0",
"ignore": "3.1.2",
"immutable": "^3.8.1",
"is": "^3.1.0",
"json-schema-defaults": "0.1.1",
"jsonschema": "1.1.0",
"juice": "1.10.0",
"juice": "1.11.0",
"merge-defaults": "0.2.1",
"mkdirp": "0.5.1",
"moment": "2.13.0",
"npm": "3.8.8",
"npm": "3.9.2",
"npmi": "2.0.1",
"nunjucks": "2.4.2",
"nunjucks-do": "1.0.0",
@@ -61,13 +61,13 @@
"urijs": "1.18.0"
},
"devDependencies": {
"eslint": "2.9.0",
"eslint": "2.10.2",
"expect": "^1.20.1",
"mocha": "^2.4.5"
},
"scripts": {
"lint": "eslint .",
"test": "./node_modules/.bin/mocha ./testing/setup.js './lib/**/*/__tests__/*.js' --bail --reporter=list --timeout=10000"
"test": "./node_modules/.bin/mocha ./testing/setup.js \"./lib/**/*/__tests__/*.js\" --bail --reporter=list --timeout=10000"
},
"repository": {
"type": "git",