diff options
Diffstat (limited to 'lib/utils')
-rw-r--r-- | lib/utils/code.js | 36 | ||||
-rw-r--r-- | lib/utils/fs.js | 4 | ||||
-rw-r--r-- | lib/utils/git.js | 23 | ||||
-rw-r--r-- | lib/utils/navigation.js | 9 | ||||
-rw-r--r-- | lib/utils/page.js | 41 | ||||
-rw-r--r-- | lib/utils/path.js | 39 | ||||
-rw-r--r-- | lib/utils/watch.js | 1 |
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 }); |