summaryrefslogtreecommitdiffstats
path: root/lib/utils
diff options
context:
space:
mode:
Diffstat (limited to 'lib/utils')
-rw-r--r--lib/utils/batch.js52
-rw-r--r--lib/utils/fs.js193
-rw-r--r--lib/utils/git.js127
-rw-r--r--lib/utils/i18n.js80
-rw-r--r--lib/utils/images.js37
-rw-r--r--lib/utils/links.js81
-rw-r--r--lib/utils/logger.js102
-rw-r--r--lib/utils/navigation.js79
-rw-r--r--lib/utils/page.js397
-rw-r--r--lib/utils/path.js8
-rw-r--r--lib/utils/progress.js55
-rw-r--r--lib/utils/server.js94
-rw-r--r--lib/utils/string.js27
-rw-r--r--lib/utils/watch.js40
14 files changed, 4 insertions, 1368 deletions
diff --git a/lib/utils/batch.js b/lib/utils/batch.js
deleted file mode 100644
index 9069766..0000000
--- a/lib/utils/batch.js
+++ /dev/null
@@ -1,52 +0,0 @@
-var Q = require("q");
-var _ = require("lodash");
-
-// Execute a method for all element
-function execEach(items, options) {
- if (_.size(items) === 0) return Q();
- var concurrents = 0, d = Q.defer(), pending = [];
-
- options = _.defaults(options || {}, {
- max: 100,
- fn: function() {}
- });
-
-
- function startItem(item, i) {
- if (concurrents >= options.max) {
- pending.push([item, i]);
- return;
- }
-
- concurrents++;
- Q()
- .then(function() {
- return options.fn(item, i);
- })
- .then(function() {
- concurrents--;
-
- // Next pending
- var next = pending.shift();
-
- if (concurrents === 0 && !next) {
- d.resolve();
- } else if (next) {
- startItem.apply(null, next);
- }
- })
- .fail(function(err) {
- pending = [];
- d.reject(err);
- });
- }
-
- _.each(items, startItem);
-
- return d.promise;
-}
-
-module.exports = {
- execEach: execEach
-};
-
diff --git a/lib/utils/fs.js b/lib/utils/fs.js
deleted file mode 100644
index b82701f..0000000
--- a/lib/utils/fs.js
+++ /dev/null
@@ -1,193 +0,0 @@
-var _ = require('lodash');
-var Q = require('q');
-var tmp = require('tmp');
-var path = require('path');
-var fs = require('graceful-fs');
-var fsExtra = require('fs-extra');
-var Ignore = require('fstream-ignore');
-
-var fsUtils = {
- tmp: {
- file: function(opt) {
- return Q.nfcall(tmp.file.bind(tmp), opt).get(0);
- },
- dir: function() {
- return Q.nfcall(tmp.dir.bind(tmp)).get(0);
- }
- },
- list: listFiles,
- stat: Q.denodeify(fs.stat),
- readdir: Q.denodeify(fs.readdir),
- readFile: Q.denodeify(fs.readFile),
- writeFile: writeFile,
- writeStream: writeStream,
- mkdirp: Q.denodeify(fsExtra.mkdirp),
- copy: Q.denodeify(fsExtra.copy),
- remove: Q.denodeify(fsExtra.remove),
- symlink: Q.denodeify(fsExtra.symlink),
- exists: function(path) {
- var d = Q.defer();
- fs.exists(path, d.resolve);
- return d.promise;
- },
- findFile: findFile,
- existsSync: fs.existsSync.bind(fs),
- readFileSync: fs.readFileSync.bind(fs),
- clean: cleanFolder,
- getUniqueFilename: getUniqueFilename
-};
-
-// Write a file
-function writeFile(filename, data, options) {
- var d = Q.defer();
-
- try {
- fs.writeFileSync(filename, data, options);
- } catch(err) {
- d.reject(err);
- }
- d.resolve();
-
-
- return d.promise;
-}
-
-// Write a stream to a file
-function writeStream(filename, st) {
- var d = Q.defer();
-
- var wstream = fs.createWriteStream(filename);
-
- wstream.on('finish', function () {
- d.resolve();
- });
- wstream.on('error', function (err) {
- d.reject(err);
- });
-
- st.on('error', function(err) {
- d.reject(err);
- });
-
- st.pipe(wstream);
-
- return d.promise;
-}
-
-// Find a filename available
-function getUniqueFilename(base, filename) {
- if (!filename) {
- filename = base;
- base = '/';
- }
-
- filename = path.resolve(base, filename);
- var ext = path.extname(filename);
- filename = path.join(path.dirname(filename), path.basename(filename, ext));
-
- var _filename = filename+ext;
-
- var i = 0;
- while (fs.existsSync(filename)) {
- _filename = filename+'_'+i+ext;
- i = i + 1;
- }
-
- return path.relative(base, _filename);
-}
-
-
-// List files in a directory
-function listFiles(root, options) {
- options = _.defaults(options || {}, {
- ignoreFiles: [],
- ignoreRules: []
- });
-
- var d = Q.defer();
-
- // Our list of files
- var files = [];
-
- var ig = Ignore({
- path: root,
- ignoreFiles: options.ignoreFiles
- });
-
- // Add extra rules to ignore common folders
- ig.addIgnoreRules(options.ignoreRules, '__custom_stuff');
-
- // Push each file to our list
- ig.on('child', function (c) {
- files.push(
- c.path.substr(c.root.path.length + 1) + (c.props.Directory === true ? '/' : '')
- );
- });
-
- ig.on('end', function() {
- // Normalize paths on Windows
- if(process.platform === 'win32') {
- return d.resolve(files.map(function(file) {
- return file.replace(/\\/g, '/');
- }));
- }
-
- // Simply return paths otherwise
- return d.resolve(files);
- });
-
- ig.on('error', d.reject);
-
- return d.promise;
-}
-
-// Clean a folder without removing .git and .svn
-// Creates it if non existant
-function cleanFolder(root) {
- if (!fs.existsSync(root)) return fsUtils.mkdirp(root);
-
- return listFiles(root, {
- ignoreFiles: [],
- ignoreRules: [
- // Skip Git and SVN stuff
- '.git/',
- '.svn/'
- ]
- })
- .then(function(files) {
- var d = Q.defer();
-
- _.reduce(files, function(prev, file, i) {
- return prev.then(function() {
- var _file = path.join(root, file);
-
- d.notify({
- i: i+1,
- count: files.length,
- file: _file
- });
- return fsUtils.remove(_file);
- });
- }, Q())
- .then(function() {
- d.resolve();
- }, function(err) {
- d.reject(err);
- });
-
- return d.promise;
- });
-}
-
-// Find a file in a folder (case incensitive)
-// Return the real filename
-function findFile(root, filename) {
- return Q.nfcall(fs.readdir, root)
- .then(function(files) {
- return _.find(files, function(file) {
- return (file.toLowerCase() == filename.toLowerCase());
- });
- });
-}
-
-module.exports = fsUtils;
diff --git a/lib/utils/git.js b/lib/utils/git.js
deleted file mode 100644
index 72c8818..0000000
--- a/lib/utils/git.js
+++ /dev/null
@@ -1,127 +0,0 @@
-var Q = require('q');
-var _ = require('lodash');
-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');
-
-var GIT_PREFIX = 'git+';
-var GIT_TMP = null;
-
-
-// Check if an url is a git dependency url
-function checkGitUrl(giturl) {
- return (giturl.indexOf(GIT_PREFIX) === 0);
-}
-
-// Validates a SHA in hexadecimal
-function validateSha(str) {
- return (/[0-9a-f]{40}/).test(str);
-}
-
-// Parse and extract infos
-function parseGitUrl(giturl) {
- var ref, uri, fileParts, filepath;
-
- if (!checkGitUrl(giturl)) return null;
- giturl = giturl.slice(GIT_PREFIX.length);
-
- uri = new URI(giturl);
- ref = uri.fragment() || 'master';
- uri.fragment(null);
-
- // Extract file inside the repo (after the .git)
- fileParts =uri.path().split('.git');
- filepath = fileParts.length > 1? fileParts.slice(1).join('.git') : '';
- if (filepath[0] == '/') filepath = filepath.slice(1);
-
- // Recreate pathname without the real filename
- uri.path(_.first(fileParts)+'.git');
-
- return {
- host: uri.toString(),
- ref: ref || 'master',
- filepath: filepath
- };
-}
-
-// Clone a git repo from a specific ref
-function cloneGitRepo(host, ref) {
- var isBranch = false;
-
- ref = ref || 'master';
- if (!validateSha(ref)) isBranch = true;
-
- return Q()
-
- // Create temporary folder to store git repos
- .then(function() {
- if (GIT_TMP) return;
- return fs.tmp.dir()
- .then(function(_tmp) {
- GIT_TMP = _tmp;
- });
- })
-
- // Return or clone the git repo
- .then(function() {
- // Unique ID for repo/ref combinaison
- var repoId = crc.crc32(host+'#'+ref).toString(16);
-
- // Absolute path to the folder
- var repoPath = path.resolve(GIT_TMP, repoId);
-
- return fs.exists(repoPath)
- .then(function(doExists) {
- if (doExists) return;
-
- // Clone repo
- 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);
- if (!giturl) return Q(null);
-
- // Clone or get from cache
- return cloneGitRepo(giturl.host, giturl.ref)
- .then(function(repo) {
-
- // Resolve relative path
- return path.resolve(repo, giturl.filepath);
- });
-}
-
-// 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,
- resolveRoot: resolveGitRoot
-};
diff --git a/lib/utils/i18n.js b/lib/utils/i18n.js
deleted file mode 100644
index de64b49..0000000
--- a/lib/utils/i18n.js
+++ /dev/null
@@ -1,80 +0,0 @@
-var _ = require('lodash');
-var path = require('path');
-var fs = require('fs');
-
-var i18n = require('i18n');
-
-var I18N_PATH = path.resolve(__dirname, '../../theme/i18n/');
-var DEFAULT_LANGUAGE = 'en';
-var LOCALES = _.map(fs.readdirSync(I18N_PATH), function(lang) {
- return path.basename(lang, '.json');
-});
-
-i18n.configure({
- locales: LOCALES,
- directory: I18N_PATH,
- defaultLocale: DEFAULT_LANGUAGE,
- updateFiles: false
-});
-
-function compareLocales(lang, locale) {
- var langMain = _.first(lang.split('-'));
- var langSecond = _.last(lang.split('-'));
-
- var localeMain = _.first(locale.split('-'));
- var localeSecond = _.last(locale.split('-'));
-
- if (locale == lang) return 100;
- if (localeMain == langMain) return 50;
- if (localeSecond == langSecond) return 20;
- return 0;
-}
-
-var normalizeLanguage = _.memoize(function(lang) {
- var language = _.chain(LOCALES)
- .values()
- .map(function(locale) {
- return {
- locale: locale,
- score: compareLocales(lang, locale)
- };
- })
- .filter(function(lang) {
- return lang.score > 0;
- })
- .sortBy('score')
- .pluck('locale')
- .last()
- .value();
- return language || lang;
-});
-
-function translate(locale, phrase) {
- var args = Array.prototype.slice.call(arguments, 2);
-
- return i18n.__.apply({}, [{
- locale: locale,
- phrase: phrase
- }].concat(args));
-}
-
-function getCatalog(locale) {
- locale = normalizeLanguage(locale);
- return i18n.getCatalog(locale);
-}
-
-function getLocales() {
- return LOCALES;
-}
-
-function hasLocale(locale) {
- return _.contains(LOCALES, locale);
-}
-
-module.exports = {
- __: translate,
- normalizeLanguage: normalizeLanguage,
- getCatalog: getCatalog,
- getLocales: getLocales,
- hasLocale: hasLocale
-};
diff --git a/lib/utils/images.js b/lib/utils/images.js
deleted file mode 100644
index a82b0a1..0000000
--- a/lib/utils/images.js
+++ /dev/null
@@ -1,37 +0,0 @@
-var _ = require("lodash");
-var Q = require("q");
-var fs = require("./fs");
-var spawn = require("spawn-cmd").spawn;
-
-// Convert a svg file
-var convertSVG = function(source, dest, options) {
- if (!fs.existsSync(source)) return Q.reject(new Error("File doesn't exist: "+source));
- var d = Q.defer();
-
- options = _.defaults(options || {}, {
-
- });
-
- //var command = shellescape(["svgexport", source, dest]);
- var child = spawn("svgexport", [source, dest]);
-
- child.on("error", function(error) {
- if (error.code == "ENOENT") error = new Error("Need to install \"svgexport\" using \"npm install svgexport -g\"");
- return d.reject(error);
- });
-
- child.on("close", function(code) {
- if (code === 0 && fs.existsSync(dest)) {
- d.resolve();
- } else {
- d.reject(new Error("Error converting "+source+" into "+dest));
- }
- });
-
- return d.promise;
-};
-
-module.exports = {
- convertSVG: convertSVG,
- INVALID: [".svg"]
-};
diff --git a/lib/utils/links.js b/lib/utils/links.js
deleted file mode 100644
index 5122396..0000000
--- a/lib/utils/links.js
+++ /dev/null
@@ -1,81 +0,0 @@
-var url = require('url');
-var path = require('path');
-
-// Is the link an external link
-function isExternal(href) {
- try {
- return Boolean(url.parse(href).protocol);
- } catch(err) {
- return false;
- }
-}
-
-// Return true if the link is relative
-function isRelative(href) {
- try {
- var parsed = url.parse(href);
-
- return !!(!parsed.protocol && parsed.path);
- } catch(err) {
- return true;
- }
-}
-
-// Return true if the link is an achor
-function isAnchor(href) {
- try {
- var parsed = url.parse(href);
- return !!(!parsed.protocol && !parsed.path && parsed.hash);
- } catch(err) {
- return false;
- }
-}
-
-// Normalize a path to be a link
-function normalizeLink(s) {
- return s.replace(/\\/g, '/');
-}
-
-// Relative to absolute path
-// dir: directory parent of the file currently in rendering process
-// outdir: directory parent from the html output
-function toAbsolute(_href, dir, outdir) {
- if (isExternal(_href)) return _href;
-
- // Path "_href" inside the base folder
- var hrefInRoot = path.normalize(path.join(dir, _href));
- if (_href[0] == '/') hrefInRoot = path.normalize(_href.slice(1));
-
- // Make it relative to output
- _href = path.relative(outdir, hrefInRoot);
-
- // Normalize windows paths
- _href = normalizeLink(_href);
-
- return _href;
-}
-
-// Join links
-function join() {
- var _href = path.join.apply(path, arguments);
-
- return normalizeLink(_href);
-};
-
-// Change extension
-function changeExtension(filename, newext) {
- return path.join(
- path.dirname(filename),
- path.basename(filename, path.extname(filename))+newext
- );
-}
-
-module.exports = {
- isAnchor: isAnchor,
- isRelative: isRelative,
- isExternal: isExternal,
- toAbsolute: toAbsolute,
- join: join,
- changeExtension: changeExtension,
- normalize: normalizeLink
-};
diff --git a/lib/utils/logger.js b/lib/utils/logger.js
deleted file mode 100644
index db3d90e..0000000
--- a/lib/utils/logger.js
+++ /dev/null
@@ -1,102 +0,0 @@
-var _ = require("lodash");
-var util = require("util");
-var color = require("bash-color");
-
-var LEVELS = {
- DEBUG: 0,
- INFO: 1,
- WARN: 2,
- ERROR: 3,
- DISABLED: 10
-};
-
-var COLORS = {
- DEBUG: color.purple,
- INFO: color.cyan,
- WARN: color.yellow,
- ERROR: color.red
-};
-
-module.exports = function(_write, logLevel) {
- var logger = {};
- var lastChar = "\n";
- if (_.isString(logLevel)) logLevel = LEVELS[logLevel.toUpperCase()];
-
- // Write a simple message
- logger.write = function(msg) {
- msg = msg.toString();
- lastChar = _.last(msg);
- return _write(msg);
- };
-
- // Format a message
- logger.format = function() {
- return util.format.apply(util, arguments);
- };
-
- // Write a line
- logger.writeLn = function(msg) {
- return this.write((msg || "")+"\n");
- };
-
- // Write a message with a certain level
- logger.log = function(level) {
- if (level < logLevel) return;
-
- var levelKey = _.findKey(LEVELS, function(v) { return v == level; });
- var args = Array.prototype.slice.apply(arguments, [1]);
- var msg = logger.format.apply(logger, args);
-
- if (lastChar == "\n") {
- msg = COLORS[levelKey](levelKey.toLowerCase()+":")+" "+msg;
- }
-
- return logger.write(msg);
- };
- logger.logLn = function() {
- if (lastChar != "\n") logger.write("\n");
-
- var args = Array.prototype.slice.apply(arguments);
- args.push("\n");
- logger.log.apply(logger, args);
- };
-
- // Write a OK
- logger.ok = function(level) {
- var args = Array.prototype.slice.apply(arguments, [1]);
- var msg = logger.format.apply(logger, args);
- if (arguments.length > 1) {
- logger.logLn(level, color.green(">> ") + msg.trim().replace(/\n/g, color.green("\n>> ")));
- } else {
- logger.log(level, color.green("OK"), "\n");
- }
- };
-
- // Write an "FAIL"
- logger.fail = function(level) {
- return logger.log(level, color.red("ERROR")+"\n");
- };
-
- _.each(_.omit(LEVELS, "DISABLED"), function(level, levelKey) {
- levelKey = levelKey.toLowerCase();
-
- logger[levelKey] = _.partial(logger.log, level);
- logger[levelKey].ln = _.partial(logger.logLn, level);
- logger[levelKey].ok = _.partial(logger.ok, level);
- logger[levelKey].fail = _.partial(logger.fail, level);
- logger[levelKey].promise = function(p) {
- return p.
- then(function(st) {
- logger[levelKey].ok();
- return st;
- }, function(err) {
- logger[levelKey].fail();
- throw err;
- });
- };
- });
-
- return logger;
-};
-module.exports.LEVELS = LEVELS;
-module.exports.COLORS = COLORS;
diff --git a/lib/utils/navigation.js b/lib/utils/navigation.js
deleted file mode 100644
index d07eb35..0000000
--- a/lib/utils/navigation.js
+++ /dev/null
@@ -1,79 +0,0 @@
-var _ = require("lodash");
-
-// Cleans up an article/chapter object
-// remove "articles" attributes
-function clean(obj) {
- return obj && _.omit(obj, ["articles"]);
-}
-
-function flattenChapters(chapters) {
- return _.reduce(chapters, function(accu, chapter) {
- return accu.concat([clean(chapter)].concat(flattenChapters(chapter.articles)));
- }, []);
-}
-
-// Returns from a summary a map of
-/*
- {
- "file/path.md": {
- prev: ...,
- next: ...,
- },
- ...
- }
-*/
-function navigation(summary, files) {
- // Support single files as well as list
- files = _.isArray(files) ? files : (_.isString(files) ? [files] : null);
-
- // List of all navNodes
- // Flatten chapters
- var navNodes = flattenChapters(summary.chapters);
-
- // Mapping of prev/next for a give path
- var mapping = _.chain(navNodes)
- .map(function(current, i) {
- var prev = null, next = null;
-
- // Skip if no path
- if(!current.exists) return null;
-
- // Find prev
- prev = _.chain(navNodes.slice(0, i))
- .reverse()
- .find(function(node) {
- return node.exists && !node.external;
- })
- .value();
-
- // Find next
- next = _.chain(navNodes.slice(i+1))
- .find(function(node) {
- return node.exists && !node.external;
- })
- .value();
-
- return [current.path, {
- index: i,
- title: current.title,
- introduction: current.introduction,
- prev: prev,
- next: next,
- level: current.level,
- }];
- })
- .compact()
- .object()
- .value();
-
- // Filter for only files we want
- if(files) {
- return _.pick(mapping, files);
- }
-
- return mapping;
-}
-
-
-// Exports
-module.exports = navigation;
diff --git a/lib/utils/page.js b/lib/utils/page.js
deleted file mode 100644
index 010d703..0000000
--- a/lib/utils/page.js
+++ /dev/null
@@ -1,397 +0,0 @@
-var Q = require('q');
-var _ = require('lodash');
-var url = require('url');
-var path = require('path');
-var cheerio = require('cheerio');
-var domSerializer = require('dom-serializer');
-var request = require('request');
-var crc = require('crc');
-var slug = require('github-slugid');
-
-var links = require('./links');
-var imgUtils = require('./images');
-var fs = require('./fs');
-var batch = require('./batch');
-
-var parsableExtensions = require('gitbook-parsers').extensions;
-
-// Map of images that have been converted
-var imgConversionCache = {};
-
-// Render a cheerio dom as html
-function renderDom($, dom, options) {
- if (!dom && $._root && $._root.children) {
- dom = $._root.children;
- }
-
- options = options|| dom.options || $._options;
- return domSerializer(dom, options);
-}
-
-function replaceText($, el, search, replace, text_only ) {
- return $(el).each(function(){
- var node = this.firstChild,
- val,
- new_val,
-
- // Elements to be removed at the end.
- remove = [];
-
- // Only continue if firstChild exists.
- if ( node ) {
-
- // Loop over all childNodes.
- while (node) {
-
- // Only process text nodes.
- if ( node.nodeType === 3 ) {
-
- // The original node value.
- val = node.nodeValue;
-
- // The new value.
- new_val = val.replace( search, replace );
-
- // Only replace text if the new value is actually different!
- if ( new_val !== val ) {
-
- if ( !text_only && /</.test( new_val ) ) {
- // The new value contains HTML, set it in a slower but far more
- // robust way.
- $(node).before( new_val );
-
- // Don't remove the node yet, or the loop will lose its place.
- remove.push( node );
- } else {
- // The new value contains no HTML, so it can be set in this
- // very fast, simple way.
- node.nodeValue = new_val;
- }
- }
- }
-
- node = node.nextSibling;
- }
- }
-
- // Time to remove those elements!
- if (remove.length) $(remove).remove();
- });
-}
-
-function pregQuote( str ) {
- return (str+'').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, '\\$1');
-}
-
-
-// Adapt an html snippet to be relative to a base folder
-function normalizeHtml(src, options) {
- var $ = cheerio.load(src, {
- // We should parse html without trying to normalize too much
- xmlMode: false,
-
- // SVG need some attributes to use uppercases
- lowerCaseAttributeNames: false,
- lowerCaseTags: false
- });
- var toConvert = [];
- var svgContent = {};
- var outputRoot = options.book.options.output;
-
- imgConversionCache[outputRoot] = imgConversionCache[outputRoot] || {};
-
- // Find svg images to extract and process
- if (options.convertImages) {
- $('svg').each(function() {
- var content = renderDom($, $(this));
- var svgId = _.uniqueId('svg');
- var dest = svgId+'.svg';
-
- // Generate filename
- dest = '/'+fs.getUniqueFilename(outputRoot, dest);
-
- svgContent[dest] = '<?xml version="1.0" encoding="UTF-8"?>'+content;
- $(this).replaceWith($('<img>').attr('src', dest));
- });
- }
-
- // Generate ID for headings
- $('h1,h2,h3,h4,h5,h6').each(function() {
- if ($(this).attr('id')) return;
-
- $(this).attr('id', slug($(this).text()));
- });
-
- // Find images to normalize
- $('img').each(function() {
- var origin;
- var src = $(this).attr('src');
-
- if (!src) return;
- var isExternal = links.isExternal(src);
-
- // Transform as relative to the bases
- if (links.isRelative(src)) {
- src = links.toAbsolute(src, options.base, options.output);
- }
-
- // Convert if needed
- if (options.convertImages) {
- // If image is external and ebook, then downlaod the images
- if (isExternal) {
- origin = src;
- src = '/'+crc.crc32(origin).toString(16)+path.extname(url.parse(origin).pathname);
- src = links.toAbsolute(src, options.base, options.output);
- isExternal = false;
- }
-
- var ext = path.extname(src);
- var srcAbs = links.join('/', options.base, src);
-
- // Test image extension
- if (_.contains(imgUtils.INVALID, ext)) {
- if (imgConversionCache[outputRoot][srcAbs]) {
- // Already converted
- src = imgConversionCache[outputRoot][srcAbs];
- } else {
- // Not converted yet
- var dest = '';
-
- // Replace extension
- dest = links.join(path.dirname(srcAbs), path.basename(srcAbs, ext)+'.png');
- dest = dest[0] == '/'? dest.slice(1) : dest;
-
- // Get a name that doesn't exists
- dest = fs.getUniqueFilename(outputRoot, dest);
-
- options.book.log.debug.ln('detect invalid image (will be converted to png):', srcAbs);
-
- // Add to cache
- imgConversionCache[outputRoot][srcAbs] = '/'+dest;
-
- // Push to convert
- toConvert.push({
- origin: origin,
- content: svgContent[srcAbs],
- source: isExternal? srcAbs : path.join('./', srcAbs),
- dest: path.join('./', dest)
- });
-
- src = links.join('/', dest);
- }
-
- // Reset as relative to output
- src = links.toAbsolute(src, options.base, options.output);
- }
-
- else if (origin) {
- // Need to downlaod image
- toConvert.push({
- origin: origin,
- source: path.join('./', srcAbs)
- });
- }
- }
-
- $(this).attr('src', src);
- });
-
- // Normalize links
- $('a').each(function() {
- var href = $(this).attr('href');
- if (!href) return;
-
- if (links.isAnchor(href)) {
- // Keep it as it is
- } else if (links.isRelative(href)) {
- var parts = url.parse(href);
-
- var pathName = decodeURIComponent(parts.pathname);
- var anchor = parts.hash || '';
-
- // Calcul absolute path for this file (without the anchor)
- var absolutePath = links.join(options.base, pathName);
-
- // 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 {
- // External links
- $(this).attr('target', '_blank');
- }
-
- // Transform extension
- $(this).attr('href', href);
- });
-
- // Highlight code blocks
- $('code').each(function() {
- // 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();
-
- var source = $(this).text();
- var blk = options.book.template.applyBlock('code', {
- body: source,
- kwargs: {
- language: lang
- }
- });
-
- if (blk.html === false) $(this).text(blk.body);
- else $(this).html(blk.body);
- });
-
- // Replace glossary terms
- var glossary = _.sortBy(options.glossary, function(term) {
- return -term.name.length;
- });
-
- _.each(glossary, function(term) {
- var r = new RegExp( '\\b(' + pregQuote(term.name.toLowerCase()) + ')\\b' , 'gi' );
- var includedInFiles = false;
-
- $('*').each(function() {
- // Ignore codeblocks
- if (_.contains(['code', 'pre', 'a', 'script'], this.name.toLowerCase())) return;
-
- replaceText($, this, r, function(match) {
- // Add to files index in glossary
- if (!includedInFiles) {
- includedInFiles = true;
- term.files = term.files || [];
- term.files.push(options.navigation[options.input]);
- }
- return '<a href=\''+links.toAbsolute('/GLOSSARY.html', options.base, options.output) + '#' + term.id+'\' class=\'glossary-term\' title=\''+_.escape(term.description)+'\'>'+match+'</a>';
- });
- });
- });
-
- return {
- html: renderDom($),
- images: toConvert
- };
-}
-
-// Convert svg images to png
-function convertImages(images, options) {
- if (!options.convertImages) return Q();
-
- var downloaded = [];
- options.book.log.debug.ln('convert ', images.length, 'images to png');
-
- return batch.execEach(images, {
- max: 100,
- fn: function(image) {
- var imgin = path.resolve(options.book.options.output, image.source);
-
- return Q()
-
- // Write image if need to be download
- .then(function() {
- 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)))
- .fail(function(err) {
- if (!_.isError(err)) err = new Error(err);
-
- err.message = 'Fail downloading '+image.origin+': '+err.message;
- throw err;
- });
- })
-
- // Write svg if content
- .then(function() {
- if (!image.content) return;
- return fs.writeFile(imgin, image.content);
- })
-
- // Convert
- .then(function() {
- if (!image.dest) return;
- var imgout = path.resolve(options.book.options.output, image.dest);
- options.book.log.debug('convert image', image.source, 'to', image.dest, '...');
- return options.book.log.debug.promise(imgUtils.convertSVG(imgin, imgout));
- });
- }
- })
- .then(function() {
- options.book.log.debug.ok(images.length+' images converted with success');
- });
-}
-
-// Adapt page content to be relative to a base folder
-function normalizePage(sections, options) {
- options = _.defaults(options || {}, {
- // Current book
- book: null,
-
- // Do we need to convert svg?
- convertImages: false,
-
- // Current file path
- input: '.',
-
- // Navigation to use to transform path
- navigation: {},
-
- // Directory parent of the file currently in rendering process
- base: './',
-
- // Directory parent from the html output
- output: './',
-
- // Glossary terms
- glossary: []
- });
-
- // List of images to convert
- var toConvert = [];
-
- sections = _.map(sections, function(section) {
- if (section.type != 'normal') return section;
-
- var out = normalizeHtml(section.content, options);
-
- toConvert = toConvert.concat(out.images);
- section.content = out.html;
- return section;
- });
-
- return Q()
- .then(function() {
- toConvert = _.uniq(toConvert, 'source');
- return convertImages(toConvert, options);
- })
- .thenResolve(sections);
-}
-
-
-module.exports = {
- normalize: normalizePage
-};
diff --git a/lib/utils/path.js b/lib/utils/path.js
index 5285896..dc97d5d 100644
--- a/lib/utils/path.js
+++ b/lib/utils/path.js
@@ -1,5 +1,5 @@
-var _ = require("lodash");
-var path = require("path");
+var _ = require('lodash');
+var path = require('path');
// Return true if file path is inside a folder
function isInRoot(root, filename) {
@@ -26,8 +26,8 @@ function resolveInRoot(root) {
result = path.resolve(root, input);
if (!isInRoot(root, result)) {
- err = new Error("EACCESS: \"" + result + "\" not in \"" + root + "\"");
- err.code = "EACCESS";
+ err = new Error('EACCESS: "' + result + '" not in "' + root + '"');
+ err.code = 'EACCESS';
throw err;
}
diff --git a/lib/utils/progress.js b/lib/utils/progress.js
deleted file mode 100644
index 8dda892..0000000
--- a/lib/utils/progress.js
+++ /dev/null
@@ -1,55 +0,0 @@
-var _ = require('lodash');
-
-// Returns from a navigation and a current file, a snapshot of current detailed state
-function calculProgress(navigation, current) {
- var n = _.size(navigation);
- var percent = 0, prevPercent = 0, currentChapter = null;
- var done = true;
-
- var chapters = _.chain(navigation)
-
- // Transform as array
- .map(function(nav, path) {
- nav.path = path;
- return nav;
- })
-
- // Sort entries
- .sortBy(function(nav) {
- return nav.index;
- })
-
- .map(function(nav, i) {
- // Calcul percent
- nav.percent = (i * 100) / Math.max((n - 1), 1);
-
- // Is it done
- nav.done = done;
- if (nav.path == current) {
- currentChapter = nav;
- percent = nav.percent;
- done = false;
- } else if (done) {
- prevPercent = nav.percent;
- }
-
- return nav;
- })
- .value();
-
- return {
- // Previous percent
- prevPercent: prevPercent,
-
- // Current percent
- percent: percent,
-
- // List of chapter with progress
- chapters: chapters,
-
- // Current chapter
- current: currentChapter
- };
-}
-
-module.exports = calculProgress;
diff --git a/lib/utils/server.js b/lib/utils/server.js
deleted file mode 100644
index 1d6822f..0000000
--- a/lib/utils/server.js
+++ /dev/null
@@ -1,94 +0,0 @@
-var Q = require("q");
-var events = require("events");
-var http = require("http");
-var send = require("send");
-var util = require("util");
-var url = require("url");
-
-var Server = function() {
- this.running = null;
- this.dir = null;
- this.port = 0;
- this.sockets = [];
-};
-util.inherits(Server, events.EventEmitter);
-
-// Return true if the server is running
-Server.prototype.isRunning = function() {
- return !!this.running;
-};
-
-// Stop the server
-Server.prototype.stop = function() {
- var that = this;
- if (!this.isRunning()) return Q();
-
- var d = Q.defer();
- this.running.close(function(err) {
- that.running = null;
- that.emit("state", false);
-
- if (err) d.reject(err);
- else d.resolve();
- });
-
- for (var i = 0; i < this.sockets.length; i++) {
- this.sockets[i].destroy();
- }
-
- return d.promise;
-};
-
-Server.prototype.start = function(dir, port) {
- var that = this, pre = Q();
- port = port || 8004;
-
- if (that.isRunning()) pre = this.stop();
- return pre
- .then(function() {
- var d = Q.defer();
-
- that.running = http.createServer(function(req, res){
- // Render error
- function error(err) {
- res.statusCode = err.status || 500;
- res.end(err.message);
- }
-
- // Redirect to directory"s index.html
- function redirect() {
- res.statusCode = 301;
- res.setHeader("Location", req.url + "/");
- res.end("Redirecting to " + req.url + "/");
- }
-
- // Send file
- send(req, url.parse(req.url).pathname)
- .root(dir)
- .on("error", error)
- .on("directory", redirect)
- .pipe(res);
- });
-
- that.running.on("connection", function (socket) {
- that.sockets.push(socket);
- socket.setTimeout(4000);
- socket.on("close", function () {
- that.sockets.splice(that.sockets.indexOf(socket), 1);
- });
- });
-
- that.running.listen(port, function(err) {
- if (err) return d.reject(err);
-
- that.port = port;
- that.dir = dir;
- that.emit("state", true);
- d.resolve();
- });
-
- return d.promise;
- });
-};
-
-module.exports = Server;
diff --git a/lib/utils/string.js b/lib/utils/string.js
deleted file mode 100644
index caa2364..0000000
--- a/lib/utils/string.js
+++ /dev/null
@@ -1,27 +0,0 @@
-var _ = require("lodash");
-
-function escapeShellArg(arg) {
- var ret = "";
-
- ret = arg.replace(/"/g, '\\"');
-
- return "\"" + ret + "\"";
-}
-
-function optionsToShellArgs(options) {
- return _.chain(options)
- .map(function(value, key) {
- if (value === null || value === undefined || value === false) return null;
- if (value === true) return key;
- return key+"="+escapeShellArg(value);
- })
- .compact()
- .value()
- .join(" ");
-}
-
-module.exports = {
- escapeShellArg: escapeShellArg,
- optionsToShellArgs: optionsToShellArgs,
- toLowerCase: String.prototype.toLowerCase.call.bind(String.prototype.toLowerCase)
-};
diff --git a/lib/utils/watch.js b/lib/utils/watch.js
deleted file mode 100644
index 4d1a752..0000000
--- a/lib/utils/watch.js
+++ /dev/null
@@ -1,40 +0,0 @@
-var Q = require("q");
-var _ = require("lodash");
-var path = require("path");
-var chokidar = require("chokidar");
-
-var parsers = require("gitbook-parsers");
-
-function watch(dir) {
- var d = Q.defer();
- dir = path.resolve(dir);
-
- var toWatch = [
- "book.json", "book.js"
- ];
-
- _.each(parsers.extensions, function(ext) {
- toWatch.push("**/*"+ext);
- });
-
- var watcher = chokidar.watch(toWatch, {
- cwd: dir,
- ignored: "_book/**",
- ignoreInitial: true
- });
-
- watcher.once("all", function(e, filepath) {
- watcher.close();
-
- d.resolve(filepath);
- });
- watcher.once("error", function(err) {
- watcher.close();
-
- d.reject(err);
- });
-
- return d.promise;
-}
-
-module.exports = watch;