summaryrefslogtreecommitdiffstats
path: root/lib/utils
diff options
context:
space:
mode:
Diffstat (limited to 'lib/utils')
-rw-r--r--lib/utils/code.js36
-rw-r--r--lib/utils/fs.js4
-rw-r--r--lib/utils/git.js23
-rw-r--r--lib/utils/navigation.js9
-rw-r--r--lib/utils/page.js41
-rw-r--r--lib/utils/path.js39
-rw-r--r--lib/utils/watch.js1
7 files changed, 98 insertions, 55 deletions
diff --git a/lib/utils/code.js b/lib/utils/code.js
deleted file mode 100644
index 0d98869..0000000
--- a/lib/utils/code.js
+++ /dev/null
@@ -1,36 +0,0 @@
-var hljs = require('highlight.js');
-
-var MAP = {
- 'py': 'python',
- 'js': 'javascript',
- 'json': 'javascript',
- 'rb': 'ruby',
- 'csharp': 'cs',
-};
-
-function normalize(lang) {
- if(!lang) { return null; }
-
- var lower = lang.toLowerCase();
- return MAP[lower] || lower;
-}
-
-function highlight(lang, code) {
- if(!lang) return code;
-
- // Normalize lang
- lang = normalize(lang);
-
- try {
- return hljs.highlight(lang, code).value;
- } catch(e) { }
-
- return code;
-}
-
-// Exports
-module.exports = {
- highlight: highlight,
- normalize: normalize,
- MAP: MAP
-};
diff --git a/lib/utils/fs.js b/lib/utils/fs.js
index 98a3a87..176a215 100644
--- a/lib/utils/fs.js
+++ b/lib/utils/fs.js
@@ -64,6 +64,10 @@ function writeStream(filename, st) {
d.reject(err);
});
+ st.on('error', function(err) {
+ d.reject(err);
+ });
+
st.pipe(wstream);
return d.promise;
diff --git a/lib/utils/git.js b/lib/utils/git.js
index 2c3dd3f..6eb9681 100644
--- a/lib/utils/git.js
+++ b/lib/utils/git.js
@@ -6,6 +6,7 @@ var path = require("path");
var crc = require("crc");
var exec = Q.denodeify(require("child_process").exec);
var URI = require("URIjs");
+var pathUtil = require("./path");
var fs = require("./fs");
@@ -83,13 +84,12 @@ function cloneGitRepo(host, ref) {
return exec("git clone "+host+" "+repoPath)
.then(function() {
return exec("git checkout "+ref, { cwd: repoPath });
- })
+ });
})
.thenResolve(repoPath);
});
}
-
// Get file from a git repo
function resolveFileFromGit(giturl) {
if (_.isString(giturl)) giturl = parseGitUrl(giturl);
@@ -104,9 +104,26 @@ function resolveFileFromGit(giturl) {
});
};
+// Return root of git repo from a filepath
+function resolveGitRoot(filepath) {
+ var relativeToGit, repoId
+
+ // No git repo cloned, or file is not in a git repository
+ if (!GIT_TMP || !pathUtil.isInRoot(GIT_TMP, filepath)) return null;
+
+ // Extract first directory (is the repo id)
+ relativeToGit = path.relative(GIT_TMP, filepath);
+ repoId = _.first(relativeToGit.split(path.sep));
+ if (!repoId) return;
+
+ // Return an absolute file
+ return path.resolve(GIT_TMP, repoId);
+};
+
module.exports = {
checkUrl: checkGitUrl,
parseUrl: parseGitUrl,
- resolveFile: resolveFileFromGit
+ resolveFile: resolveFileFromGit,
+ resolveRoot: resolveGitRoot
};
diff --git a/lib/utils/navigation.js b/lib/utils/navigation.js
index af9330d..d825c2c 100644
--- a/lib/utils/navigation.js
+++ b/lib/utils/navigation.js
@@ -27,7 +27,7 @@ function navigation(summary, files) {
files = _.isArray(files) ? files : (_.isString(files) ? [files] : null);
// List of all navNodes
- // Flatten chapters, then add in default README node if needed etc ...
+ // Flatten chapters
var navNodes = flattenChapters(summary.chapters);
// Mapping of prev/next for a give path
@@ -39,8 +39,7 @@ function navigation(summary, files) {
if(!current.exists) return null;
// Find prev
- prev = _.chain(navNodes)
- .slice(0, i)
+ prev = _.chain(navNodes.slice(0, i))
.reverse()
.find(function(node) {
return node.exists && !node.external;
@@ -48,14 +47,12 @@ function navigation(summary, files) {
.value();
// Find next
- next = _.chain(navNodes)
- .slice(i+1)
+ next = _.chain(navNodes.slice(i+1))
.find(function(node) {
return node.exists && !node.external;
})
.value();
-
return [current.path, {
index: i,
title: current.title,
diff --git a/lib/utils/page.js b/lib/utils/page.js
index f24013f..5b4eca8 100644
--- a/lib/utils/page.js
+++ b/lib/utils/page.js
@@ -11,7 +11,8 @@ var links = require('./links');
var imgUtils = require('./images');
var fs = require('./fs');
var batch = require('./batch');
-var code = require('./code');
+
+var parsableExtensions = require('gitbook-parsers').extensions;
// Render a cheerio dom as html
var renderDom = function($, dom, options) {
@@ -196,11 +197,19 @@ function normalizeHtml(src, options) {
var absolutePath = links.join(options.base, parts.pathname);
var anchor = parts.hash || "";
+
// If is in navigation relative: transform as content
if (options.navigation[absolutePath]) {
absolutePath = options.book.contentLink(absolutePath);
}
+ // If md/adoc/rst files is not in summary
+ // or for ebook, signal all files that are outside the summary
+ else if (_.contains(parsableExtensions, path.extname(absolutePath))
+ || _.contains(['epub', 'pdf', 'mobi'], options.book.options.generator)) {
+ options.book.log.warn.ln("page", options.input, "contains an hyperlink to resource outside spine '"+href+"'");
+ }
+
// Transform as absolute
href = links.toAbsolute("/"+absolutePath, options.base, options.output)+anchor;
} else {
@@ -214,26 +223,32 @@ function normalizeHtml(src, options) {
// Highlight code blocks
$("code").each(function() {
- // Extract language
+ // Normalize language
var lang = _.chain(
($(this).attr("class") || "").split(" ")
)
.map(function(cl) {
+ // Markdown
if (cl.search("lang-") === 0) return cl.slice("lang-".length);
+
+ // Asciidoc
+ if (cl.search("language-") === 0) return cl.slice("language-".length);
+
return null;
})
.compact()
.first()
.value();
- if (lang) {
- var html = code.highlight(
- lang,
- $(this).text()
- );
+ var source = $(this).text();
+ var html = options.book.template.applyBlock('code', {
+ body: source,
+ kwargs: {
+ language: lang
+ }
+ }).body;
- $(this).html(html);
- }
+ $(this).html(html);
});
// Replace glossary terms
@@ -285,7 +300,13 @@ function convertImages(images, options) {
if (!image.origin && !_.contains(downloaded, image.origin)) return;
options.book.log.debug("download image", image.origin, "...");
downloaded.push(image.origin);
- return options.book.log.debug.promise(fs.writeStream(imgin, request(image.origin)));
+ return options.book.log.debug.promise(fs.writeStream(imgin, request(image.origin)))
+ .fail(function(err) {
+ if (!_.isError(err)) err = new Error(err);
+
+ err.message = 'Fail downloading '+image.origin+': '+err.message;
+ throw err;
+ });
})
// Write svg if content
diff --git a/lib/utils/path.js b/lib/utils/path.js
new file mode 100644
index 0000000..d5b98f7
--- /dev/null
+++ b/lib/utils/path.js
@@ -0,0 +1,39 @@
+var _ = require("lodash");
+var path = require('path');
+
+// Return true if file path is inside a folder
+function isInRoot(root, filename) {
+ filename = path.normalize(filename);
+ return (filename.substr(0, root.length) === root);
+}
+
+// Resolve paths in a specific folder
+// Throw error if file is outside this folder
+function resolveInRoot(root) {
+ var input = _.chain(arguments)
+ .toArray()
+ .slice(1)
+ .reduce(function(current, p, i) {
+ // Handle path relative to book root ('/README.md')
+ if (p[0] == '/' || p[0] == '\\') return p.slice(1);
+
+ return current? path.join(current, p) : path.normalize(p);
+ }, '')
+ .value();
+
+ var result = path.resolve(root, input);
+
+ if (!isInRoot(root, result)) {
+ err = new Error("EACCESS: '" + result + "' not in '" + root + "'");
+ err.code = "EACCESS";
+ throw err;
+ }
+
+ return result
+};
+
+
+module.exports = {
+ isInRoot: isInRoot,
+ resolveInRoot: resolveInRoot
+};
diff --git a/lib/utils/watch.js b/lib/utils/watch.js
index b6e18e7..3e73e47 100644
--- a/lib/utils/watch.js
+++ b/lib/utils/watch.js
@@ -19,6 +19,7 @@ function watch(dir) {
var watcher = chokidar.watch(toWatch, {
cwd: dir,
+ ignored: '_book/**',
ignoreInitial: true
});