diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/book.js | 339 | ||||
-rw-r--r-- | lib/configuration.js | 179 | ||||
-rw-r--r-- | lib/generators/website.js | 9 | ||||
-rw-r--r-- | lib/index.js | 126 | ||||
-rw-r--r-- | lib/init.js | 83 | ||||
-rw-r--r-- | lib/pluginslist.js | 52 | ||||
-rw-r--r-- | lib/utils/page.js | 146 |
7 files changed, 448 insertions, 486 deletions
diff --git a/lib/book.js b/lib/book.js index 514a719..72f0ec2 100644 --- a/lib/book.js +++ b/lib/book.js @@ -1,23 +1,22 @@ -var Q = require("q"); -var _ = require("lodash"); -var path = require("path"); -var lunr = require("lunr"); -var parsers = require("gitbook-parsers"); - -var fs = require("./utils/fs"); -var parseNavigation = require("./utils/navigation"); -var parseProgress = require("./utils/progress"); -var pageUtil = require("./utils/page"); -var pathUtil = require("./utils/path"); -var links = require("./utils/links"); -var i18n = require("./utils/i18n"); -var logger = require("./utils/logger"); - -var Configuration = require("./configuration"); -var TemplateEngine = require("./template"); -var PluginsList = require("./pluginslist"); - -var generators = require("./generators"); +var Q = require('q'); +var _ = require('lodash'); +var path = require('path'); +var parsers = require('gitbook-parsers'); + +var fs = require('./utils/fs'); +var parseNavigation = require('./utils/navigation'); +var parseProgress = require('./utils/progress'); +var pageUtil = require('./utils/page'); +var pathUtil = require('./utils/path'); +var links = require('./utils/links'); +var i18n = require('./utils/i18n'); +var logger = require('./utils/logger'); + +var Configuration = require('./configuration'); +var TemplateEngine = require('./template'); +var PluginsList = require('./pluginslist'); + +var generators = require('./generators'); var Book = function(root, context, parent) { this.context = _.defaults(context || {}, { @@ -30,7 +29,7 @@ var Book = function(root, context, parent) { }, // Log level - logLevel: "info" + logLevel: 'info' }); // Log @@ -44,7 +43,7 @@ var Book = function(root, context, parent) { // Configuration this.config = new Configuration(this, this.context.config); - Object.defineProperty(this, "options", { + Object.defineProperty(this, 'options', { get: function () { return this.config.options; } @@ -78,23 +77,13 @@ var Book = function(root, context, parent) { this.readmeFile = null; this.langsFile = null; - // Search Index - this.searchIndexEnabled = true; - this.searchIndexSize = 0; - this.searchIndex = lunr(function () { - this.ref("url"); - - this.field("title", { boost: 10 }); - this.field("body"); - }); - // Bind methods _.bindAll(this); }; // Return string representation Book.prototype.toString = function() { - return "[Book "+this.root+"]"; + return '[Book '+this.root+']'; }; // Initialize and parse the book: config, summary, glossary @@ -112,17 +101,17 @@ Book.prototype.parse = function() { return that.parseLangs() .then(function() { multilingual = that.langs.length > 0; - if (multilingual) that.log.info.ln("Parsing multilingual book, with", that.langs.length, "languages"); + if (multilingual) that.log.info.ln('Parsing multilingual book, with', that.langs.length, 'languages'); // Sub-books that inherit from the current book configuration that.books = _.map(that.langs, function(lang) { - that.log.info.ln("Preparing language book", lang.lang); + that.log.info.ln('Preparing language book', lang.lang); return new Book( path.join(that.root, lang.path), _.merge({}, that.context, { config: _.extend({}, that.options, { - "output": path.join(that.options.output, lang.lang), - "language": lang.lang + 'output': path.join(that.options.output, lang.lang), + 'language': lang.lang }) }), that @@ -165,15 +154,15 @@ Book.prototype.generate = function(generator) { var that = this; that.options.generator = generator || that.options.generator; - that.log.info.ln("start generation with", that.options.generator, "generator"); + that.log.info.ln('start generation with', that.options.generator, 'generator'); return Q() // Clean output folder .then(function() { - that.log.info("clean", that.options.generator, "generator"); + that.log.info('clean', that.options.generator, 'generator'); return fs.clean(that.options.output) .progress(function(p) { - that.log.debug.ln("remove", p.file, "("+p.i+"/"+p.count+")"); + that.log.debug.ln('remove', p.file, '('+p.i+'/'+p.count+')'); }) .then(function() { that.log.info.ok(); @@ -183,7 +172,7 @@ Book.prototype.generate = function(generator) { // Create generator .then(function() { var Generator = generators[generator]; - if (!Generator) throw "Generator \""+that.options.generator+"\" doesn't exist"; + if (!Generator) throw 'Generator \''+that.options.generator+'\' doesn\'t exist'; generator = new Generator(that); return generator.prepare(); @@ -196,43 +185,43 @@ Book.prototype.generate = function(generator) { } else { // Separate list of files into the different operations needed var ops = _.groupBy(that.files, function(file) { - if (file[file.length -1] == "/") { - return "directories"; + if (file[file.length -1] == '/') { + return 'directories'; } else if (_.contains(parsers.extensions, path.extname(file)) && that.navigation[file]) { - return "content"; + return 'content'; } else { - return "files"; + return 'files'; } }); return Q() - // First, let"s create folder + // First, let's create folder .then(function() { return _.reduce(ops.directories || [], function(prev, folder) { return prev.then(function() { - that.log.debug.ln("transferring folder", folder); + that.log.debug.ln('transferring folder', folder); return Q(generator.transferFolder(folder)); }); }, Q()); }) - // Then, let"s copy other files + // Then, let's copy other files .then(function() { return Q.all(_.map(ops.files || [], function(file) { - that.log.debug.ln("transferring file", file); + that.log.debug.ln('transferring file', file); return Q(generator.transferFile(file)); })); }) - // Finally let"s generate content + // Finally let's generate content .then(function() { var nFiles = (ops.content || []).length; return _.reduce(ops.content || [], function(prev, file, i) { return prev.then(function() { - var p = ((i*100)/nFiles).toFixed(0)+"%"; - that.log.debug.ln("processing", file, p); + var p = ((i*100)/nFiles).toFixed(0)+'%'; + that.log.debug.ln('processing', file, p); return Q(generator.convertFile(file)) .fail(function(err) { @@ -249,16 +238,16 @@ Book.prototype.generate = function(generator) { // Finish generation .then(function() { - return generator.callHook("finish:before"); + return generator.callHook('finish:before'); }) .then(function() { return generator.finish(); }) .then(function() { - return generator.callHook("finish"); + return generator.callHook('finish'); }) .then(function() { - that.log.info.ln("generation is finished"); + that.log.info.ln('generation is finished'); }); }; @@ -284,7 +273,7 @@ Book.prototype.generateFile = function(output, options) { options = _.defaults(options || {}, { ebookFormat: path.extname(output).slice(1) }); - output = output || path.resolve(book.root, "book."+options.ebookFormat); + output = output || path.resolve(book.root, 'book.'+options.ebookFormat); return fs.tmp.dir() .then(function(tmpDir) { @@ -297,13 +286,13 @@ Book.prototype.generateFile = function(output, options) { var _tmpDir = tmpDir; if (lang) { - _outputFile = _outputFile.slice(0, -path.extname(_outputFile).length)+"_"+lang+path.extname(_outputFile); + _outputFile = _outputFile.slice(0, -path.extname(_outputFile).length)+'_'+lang+path.extname(_outputFile); _tmpDir = path.join(_tmpDir, lang); } - book.log.debug.ln("copy ebook to", _outputFile); + book.log.debug.ln('copy ebook to', _outputFile); return fs.copy( - path.join(_tmpDir, "index."+options.ebookFormat), + path.join(_tmpDir, 'index.'+options.ebookFormat), _outputFile ); }; @@ -323,7 +312,7 @@ Book.prototype.generateFile = function(output, options) { } }) .then(function(n) { - book.log.info.ok(n+" file(s) generated"); + book.log.info.ok(n+' file(s) generated'); return fs.remove(tmpDir); }); @@ -335,7 +324,7 @@ Book.prototype.generateFile = function(output, options) { Book.prototype.parseConfig = function() { var that = this; - that.log.info("loading book configuration...."); + that.log.info('loading book configuration....'); return that.config.load() .then(function() { that.log.info.ok(); @@ -349,34 +338,34 @@ Book.prototype.parsePlugins = function() { // Load plugins return that.plugins.load(that.options.plugins) .then(function() { - if (_.size(that.plugins.failed) > 0) return Q.reject(new Error("Error loading plugins: "+that.plugins.failed.join(",")+". Run \"gitbook install\" to install plugins from NPM.")); + if (_.size(that.plugins.failed) > 0) return Q.reject(new Error('Error loading plugins: '+that.plugins.failed.join(',')+'. Run \'gitbook install\' to install plugins from NPM.')); - that.log.info.ok(that.plugins.count()+" plugins loaded"); - that.log.debug.ln("normalize plugins list"); + that.log.info.ok(that.plugins.count()+' plugins loaded'); + that.log.debug.ln('normalize plugins list'); }); }; // Parse readme to extract defaults title and description Book.prototype.parseReadme = function() { var that = this; - var structure = that.config.getStructure("readme"); - that.log.debug.ln("start parsing readme:", structure); + var structure = that.config.getStructure('readme'); + that.log.debug.ln('start parsing readme:', structure); return that.findFile(structure) .then(function(readme) { - if (!readme) throw "No README file"; - if (!_.contains(that.files, readme.path)) throw "README file is ignored"; + if (!readme) throw 'No README file'; + if (!_.contains(that.files, readme.path)) throw 'README file is ignored'; that.readmeFile = readme.path; that._defaultsStructure(that.readmeFile); - that.log.debug.ln("readme located at", that.readmeFile); + that.log.debug.ln('readme located at', that.readmeFile); return that.template.renderFile(that.readmeFile) .then(function(content) { return readme.parser.readme(content) .fail(function(err) { throw that.normError(err, { - name: err.name || "Readme Parse Error", + name: err.name || 'Readme Parse Error', fileName: that.readmeFile }); }); @@ -393,8 +382,8 @@ Book.prototype.parseReadme = function() { Book.prototype.parseLangs = function() { var that = this; - var structure = that.config.getStructure("langs"); - that.log.debug.ln("start parsing languages index:", structure); + var structure = that.config.getStructure('langs'); + that.log.debug.ln('start parsing languages index:', structure); return that.findFile(structure) .then(function(langs) { @@ -403,13 +392,13 @@ Book.prototype.parseLangs = function() { that.langsFile = langs.path; that._defaultsStructure(that.langsFile); - that.log.debug.ln("languages index located at", that.langsFile); + that.log.debug.ln('languages index located at', that.langsFile); return that.template.renderFile(that.langsFile) .then(function(content) { return langs.parser.langs(content) .fail(function(err) { throw that.normError(err, { - name: err.name || "Langs Parse Error", + name: err.name || 'Langs Parse Error', fileName: that.langsFile }); }); @@ -424,29 +413,29 @@ Book.prototype.parseLangs = function() { Book.prototype.parseSummary = function() { var that = this; - var structure = that.config.getStructure("summary"); - that.log.debug.ln("start parsing summary:", structure); + var structure = that.config.getStructure('summary'); + that.log.debug.ln('start parsing summary:', structure); return that.findFile(structure) .then(function(summary) { - if (!summary) throw "No SUMMARY file"; + if (!summary) throw 'No SUMMARY file'; // Remove the summary from the list of files to parse that.summaryFile = summary.path; that._defaultsStructure(that.summaryFile); that.files = _.without(that.files, that.summaryFile); - that.log.debug.ln("summary located at", that.summaryFile); + that.log.debug.ln('summary located at', that.summaryFile); return that.template.renderFile(that.summaryFile) .then(function(content) { return summary.parser.summary(content, { entryPoint: that.readmeFile, - entryPointTitle: that.i18n("SUMMARY_INTRODUCTION"), + entryPointTitle: that.i18n('SUMMARY_INTRODUCTION'), files: that.files }) .fail(function(err) { throw that.normError(err, { - name: err.name || "Summary Parse Error", + name: err.name || 'Summary Parse Error', fileName: that.summaryFile }); }); @@ -462,8 +451,8 @@ Book.prototype.parseSummary = function() { Book.prototype.parseGlossary = function() { var that = this; - var structure = that.config.getStructure("glossary"); - that.log.debug.ln("start parsing glossary: ", structure); + var structure = that.config.getStructure('glossary'); + that.log.debug.ln('start parsing glossary: ', structure); return that.findFile(structure) .then(function(glossary) { @@ -474,13 +463,13 @@ Book.prototype.parseGlossary = function() { that._defaultsStructure(that.glossaryFile); that.files = _.without(that.files, that.glossaryFile); - that.log.debug.ln("glossary located at", that.glossaryFile); + that.log.debug.ln('glossary located at', that.glossaryFile); return that.template.renderFile(that.glossaryFile) .then(function(content) { return glossary.parser.glossary(content) .fail(function(err) { throw that.normError(err, { - name: err.name || "Glossary Parse Error", + name: err.name || 'Glossary Parse Error', fileName: that.glossaryFile }); }); @@ -512,12 +501,12 @@ Book.prototype.parsePage = function(filename, options) { }); }; - that.log.debug.ln("start parsing file", filename); + that.log.debug.ln('start parsing file', filename); var extension = path.extname(filename); var filetype = parsers.get(extension); - if (!filetype) return Q.reject(new Error("Can't parse file: "+filename)); + if (!filetype) return Q.reject(new Error('Can\'t parse file: '+filename)); // Type of parser used page.type = filetype.name; @@ -531,7 +520,7 @@ Book.prototype.parsePage = function(filename, options) { // Progress in the book page.progress = parseProgress(that.navigation, filename); - that.log.debug.ln("render template", filename); + that.log.debug.ln('render template', filename); // Read file content return that.readFile(page.path) @@ -558,7 +547,7 @@ Book.prototype.parsePage = function(filename, options) { .then(function(content) { page.content = content; - that.log.debug.ln("use file parser", filetype.name, "for", filename); + that.log.debug.ln('use file parser', filetype.name, 'for', filename); return filetype.page(page.content); }) @@ -566,7 +555,7 @@ Book.prototype.parsePage = function(filename, options) { .then(function(_page) { return _.reduce(_page.sections, function(prev, section) { return prev.then(function(_sections) { - return that.template.postProcess(section.content || "") + return that.template.postProcess(section.content || '') .then(function(content) { section.content = content; return _sections.concat([section]); @@ -582,8 +571,8 @@ Book.prototype.parsePage = function(filename, options) { convertImages: options.convertImages, input: filename, navigation: that.navigation, - base: path.dirname(filename) || "./", - output: path.dirname(filename) || "./", + base: path.dirname(filename) || './', + output: path.dirname(filename) || './', glossary: that.glossary }); }) @@ -595,7 +584,6 @@ Book.prototype.parsePage = function(filename, options) { }) .then(function() { - that.indexPage(page); return page; }); }; @@ -623,6 +611,24 @@ Book.prototype.findFile = function(filename) { }, Q(null)); }; +// Format a string using a specific markup language +Book.prototype.formatString = function(extension, content) { + return Q() + .then(function() { + var filetype = parsers.get(extension); + if (!filetype) throw new Error('Filetype doesn\'t exist: '+filetype); + + return filetype.page(content); + }) + + // Merge sections + .then(function(page) { + return _.reduce(page.sections, function(content, section) { + return content + section.content; + }, ''); + }); +}; + // Check if a file exists in the book Book.prototype.fileExists = function(filename) { return fs.exists( @@ -639,7 +645,7 @@ Book.prototype.fileIsInBook = function(filename) { Book.prototype.readFile = function(filename) { return fs.readFile( this.resolve(filename), - { encoding: "utf8" } + { encoding: 'utf8' } ); }; @@ -653,28 +659,28 @@ Book.prototype.listAllFiles = function() { var that = this; return fs.list(this.root, { - ignoreFiles: [".ignore", ".gitignore", ".bookignore"], + ignoreFiles: ['.ignore', '.gitignore', '.bookignore'], ignoreRules: [ // Skip Git stuff - ".git/", - ".gitignore", + '.git/', + '.gitignore', // Skip OS X meta data - ".DS_Store", + '.DS_Store', // Skip stuff installed by plugins - "node_modules", + 'node_modules', // Skip book outputs - "_book", - "*.pdf", - "*.epub", - "*.mobi", + '_book', + '*.pdf', + '*.epub', + '*.mobi', // Skip config files - ".ignore", - ".bookignore", - "book.json", + '.ignore', + '.bookignore', + 'book.json', ] }) .then(function(_files) { @@ -693,7 +699,7 @@ Book.prototype.parentRoot = function() { return this.root; }; -// Return true if it"s a sub-book +// Return true if it's a sub-book Book.prototype.isSubBook = function() { return !!this.parent; }; @@ -722,13 +728,13 @@ Book.prototype.relative = function(p) { // Normalize a path to .html and convert README -> index Book.prototype.contentPath = function(link) { if ( - path.basename(link, path.extname(link)) == "README" || + path.basename(link, path.extname(link)) == 'README' || link == this.readmeFile ) { - link = path.join(path.dirname(link), "index"+path.extname(link)); + link = path.join(path.dirname(link), 'index'+path.extname(link)); } - link = links.changeExtension(link, ".html"); + link = links.changeExtension(link, '.html'); return link; }; @@ -737,40 +743,15 @@ Book.prototype.contentLink = function(link) { return links.normalize(this.contentPath(link)); }; -// Index a page into the search index -Book.prototype.indexPage = function(page) { - var nav = this.navigation[page.path]; - if (!nav || !this.searchIndexEnabled) return; - - this.log.debug.ln("index page", page.path); - - // Extract text from the page - var text = pageUtil.extractText(page.sections); - - // Limit size of index (to avoid #941) - this.searchIndexSize = this.searchIndexSize + text.length; - if (this.searchIndexSize > this.config.get('search.maxIndexSize')) { - this.log.warn.ln("search index is too big, indexing is now disabled"); - this.searchIndexEnabled = false; - return; - } - - this.searchIndex.add({ - url: this.contentLink(page.path), - title: nav.title, - body: text - }); -}; - // Default structure paths to an extension Book.prototype._defaultsStructure = function(filename) { var that = this; var extension = path.extname(filename); - that.readmeFile = that.readmeFile || that.config.getStructure("readme")+extension; - that.summaryFile = that.summaryFile || that.config.getStructure("summary")+extension; - that.glossaryFile = that.glossaryFile || that.config.getStructure("glossary")+extension; - that.langsFile = that.langsFile || that.config.getStructure("langs")+extension; + that.readmeFile = that.readmeFile || that.config.getStructure('readme')+extension; + that.summaryFile = that.summaryFile || that.config.getStructure('summary')+extension; + that.glossaryFile = that.glossaryFile || that.config.getStructure('glossary')+extension; + that.langsFile = that.langsFile || that.config.getStructure('langs')+extension; }; // Change output path @@ -803,87 +784,13 @@ Book.prototype.normError = function(err, opts, defs) { err.toString = function() { var attributes = []; - if (this.fileName) attributes.push("In file \""+this.fileName+"\""); - if (this.lineNumber) attributes.push("Line "+this.lineNumber); - if (this.columnNumber) attributes.push("Column "+this.columnNumber); - return (this.name || "Error")+": "+this.message+((attributes.length > 0)? " ("+attributes.join(", ")+")" : ""); + if (this.fileName) attributes.push('In file \''+this.fileName+'\''); + if (this.lineNumber) attributes.push('Line '+this.lineNumber); + if (this.columnNumber) attributes.push('Column '+this.columnNumber); + return (this.name || 'Error')+': '+this.message+((attributes.length > 0)? ' ('+attributes.join(', ')+')' : ''); }; return err; }; -// Init and return a book -Book.init = function(root, opts) { - var book = new Book(root, opts); - var extensionToUse = ".md"; - - var chaptersPaths = function(chapters) { - return _.reduce(chapters || [], function(accu, chapter) { - var o = { - title: chapter.title - }; - if (chapter.path) o.path = chapter.path; - - return accu.concat( - [o].concat(chaptersPaths(chapter.articles)) - ); - }, []); - }; - - book.log.info.ln("init book at", root); - return fs.mkdirp(root) - .then(function() { - book.log.info.ln("detect structure from SUMMARY (if it exists)"); - return book.parseSummary(); - }) - .fail(function() { - return Q(); - }) - .then(function() { - var summary = book.summaryFile || "SUMMARY.md"; - var chapters = book.summary.chapters || []; - extensionToUse = path.extname(summary); - - if (chapters.length === 0) { - chapters = [ - { - title: "Summary", - path: "SUMMARY"+extensionToUse - }, - { - title: "Introduction", - path: "README"+extensionToUse - } - ]; - } - - return Q(chaptersPaths(chapters)); - }) - .then(function(chapters) { - // Create files that don"t exist - return Q.all(_.map(chapters, function(chapter) { - if (!chapter.path) return Q(); - var absolutePath = path.resolve(book.root, chapter.path); - - return fs.exists(absolutePath) - .then(function(exists) { - if(exists) { - book.log.info.ln("found", chapter.path); - return; - } else { - book.log.info.ln("create", chapter.path); - } - - return fs.mkdirp(path.dirname(absolutePath)) - .then(function() { - return fs.writeFile(absolutePath, "# "+chapter.title+"\n"); - }); - }); - })); - }) - .then(function() { - book.log.info.ln("initialization is finished"); - }); -}; - module.exports= Book; diff --git a/lib/configuration.js b/lib/configuration.js index c8b15b8..3b6b47b 100644 --- a/lib/configuration.js +++ b/lib/configuration.js @@ -1,13 +1,13 @@ -var _ = require("lodash"); -var Q = require("q"); -var path = require("path"); -var semver = require("semver"); +var _ = require('lodash'); +var Q = require('q'); +var path = require('path'); +var semver = require('semver'); -var pkg = require("../package.json"); -var i18n = require("./utils/i18n"); +var pkg = require('../package.json'); +var i18n = require('./utils/i18n'); // Default plugins added to each books -var DEFAULT_PLUGINS = ["highlight"]; +var DEFAULT_PLUGINS = ['highlight', 'search', 'sharing', 'fontsettings']; // Check if a plugin is a default plugin // Plugin should be in the list @@ -26,29 +26,29 @@ function isDefaultPlugin(name, version) { // Normalize a list of plugins to use function normalizePluginsList(plugins, addDefaults) { // Normalize list to an array - plugins = _.isString(plugins) ? plugins.split(",") : (plugins || []); + plugins = _.isString(plugins) ? plugins.split(',') : (plugins || []); // Remove empty parts plugins = _.compact(plugins); - // Divide as {name, version} to handle format like "myplugin@1.0.0" + // Divide as {name, version} to handle format like 'myplugin@1.0.0' plugins = _.map(plugins, function(plugin) { if (plugin.name) return plugin; - var parts = plugin.split("@"); + var parts = plugin.split('@'); var name = parts[0]; var version = parts[1]; return { - "name": name, - "version": version, // optional - "isDefault": isDefaultPlugin(name, version) + 'name': name, + 'version': version, // optional + 'isDefault': isDefaultPlugin(name, version) }; }); // List plugins to remove var toremove = _.chain(plugins) .filter(function(plugin) { - return plugin.name.length > 0 && plugin.name[0] == "-"; + return plugin.name.length > 0 && plugin.name[0] == '-'; }) .map(function(plugin) { return plugin.name.slice(1); @@ -63,15 +63,15 @@ function normalizePluginsList(plugins, addDefaults) { } plugins.push({ - "name": plugin, - "isDefault": true + 'name': plugin, + 'isDefault': true }); }); } // Remove plugin that start with '-' plugins = _.filter(plugins, function(plugin) { - return !_.contains(toremove, plugin.name) && !(plugin.name.length > 0 && plugin.name[0] == "-"); + return !_.contains(toremove, plugin.name) && !(plugin.name.length > 0 && plugin.name[0] == '-'); }); // Remove duplicates @@ -89,21 +89,21 @@ var Configuration = function(book, options) { this.options = _.merge(this.options, options || {}); // options.input == book.root - Object.defineProperty(this.options, "input", { + Object.defineProperty(this.options, 'input', { get: function () { return that.book.root; } }); // options.originalInput == book.parent.root - Object.defineProperty(this.options, "originalInput", { + Object.defineProperty(this.options, 'originalInput', { get: function () { return that.book.parent? that.book.parent.root : undefined; } }); // options.originalOutput == book.parent.options.output - Object.defineProperty(this.options, "originalOutput", { + Object.defineProperty(this.options, 'originalOutput', { get: function () { return that.book.parent? that.book.parent.options.output : undefined; } @@ -129,7 +129,7 @@ Configuration.prototype.load = function() { _config = require(configPath); that.options = _.merge( that.options, - _.omit(_config, "configFile", "defaultsPlugins", "generator", "extension") + _.omit(_config, 'configFile', 'defaultsPlugins', 'generator', 'extension') ); } catch(err) { @@ -140,18 +140,18 @@ Configuration.prototype.load = function() { .then(function() { if (!that.book.isSubBook()) { if (!semver.satisfies(pkg.version, that.options.gitbook)) { - throw new Error("GitBook version doesn't satisfy version required by the book: "+that.options.gitbook); + throw new Error('GitBook version doesn\'t satisfy version required by the book: '+that.options.gitbook); } - if (that.options.gitbook != "*" && !semver.satisfies(semver.inc(pkg.version, "patch"), that.options.gitbook)) { - that.book.log.warn.ln("gitbook version specified in your book.json might be too strict for future patches, \""+(_.first(pkg.version.split("."))+".x.x")+"\" is more adequate"); + if (that.options.gitbook != '*' && !semver.satisfies(semver.inc(pkg.version, 'patch'), that.options.gitbook)) { + that.book.log.warn.ln('gitbook version specified in your book.json might be too strict for future patches, \''+(_.first(pkg.version.split('.'))+'.x.x')+'\' is more adequate'); } } - that.options.output = path.resolve(that.options.output || that.book.resolve("_book")); + that.options.output = path.resolve(that.options.output || that.book.resolve('_book')); that.options.plugins = normalizePluginsList(that.options.plugins); - that.options.defaultsPlugins = normalizePluginsList(that.options.defaultsPlugins || "", false); + that.options.defaultsPlugins = normalizePluginsList(that.options.defaultsPlugins || '', false); that.options.plugins = _.union(that.options.plugins, that.options.defaultsPlugins); - that.options.plugins = _.uniq(that.options.plugins, "name"); + that.options.plugins = _.uniq(that.options.plugins, 'name'); // Default value for text direction (from language) if (!that.options.direction) { @@ -170,7 +170,7 @@ Configuration.prototype.extend = function(options) { // Get structure file Configuration.prototype.getStructure = function(name) { - return this.options.structure[name].split(".").slice(0, -1).join("."); + return this.options.structure[name].split('.').slice(0, -1).join('.'); }; // Return normalized language @@ -185,120 +185,109 @@ Configuration.prototype.get = function(key, def) { // Default configuration Configuration.DEFAULT = { - // Options that can"t be extend - "configFile": "book", - "generator": "website", - "extension": null, + // Options that can't be extend + 'configFile': 'book', + 'generator': 'website', + 'extension': null, // Book metadats (somes are extracted from the README by default) - "title": null, - "description": null, - "isbn": null, - "language": "en", - "direction": null, - "author": null, + 'title': null, + 'description': null, + 'isbn': null, + 'language': 'en', + 'direction': null, + 'author': null, // version of gitbook to use - "gitbook": "*", - - // Search index - "search": { - "maxIndexSize": 1000000 - }, + 'gitbook': '*', // Structure - "structure": { - "langs": "LANGS.md", - "readme": "README.md", - "glossary": "GLOSSARY.md", - "summary": "SUMMARY.md" + 'structure': { + 'langs': 'LANGS.md', + 'readme': 'README.md', + 'glossary': 'GLOSSARY.md', + 'summary': 'SUMMARY.md' }, // CSS Styles - "styles": { - "website": "styles/website.css", - "print": "styles/print.css", - "ebook": "styles/ebook.css", - "pdf": "styles/pdf.css", - "mobi": "styles/mobi.css", - "epub": "styles/epub.css" + 'styles': { + 'website': 'styles/website.css', + 'print': 'styles/print.css', + 'ebook': 'styles/ebook.css', + 'pdf': 'styles/pdf.css', + 'mobi': 'styles/mobi.css', + 'epub': 'styles/epub.css' }, - // Plugins list, can contain "-name" for removing default plugins - "plugins": [], + // Plugins list, can contain '-name' for removing default plugins + 'plugins': [], // Global configuration for plugins - "pluginsConfig": { - "fontSettings": { - "theme": null, //"sepia", "night" or "white", - "family": "sans",// "serif" or "sans", - "size": 2 // 1 - 4 - } - }, + 'pluginsConfig': {}, // Variables for templating - "variables": {}, + 'variables': {}, // Set another theme with your own layout - // It"s recommended to use plugins or add more options for default theme, though + // It's recommended to use plugins or add more options for default theme, though // See https://github.com/GitbookIO/gitbook/issues/209 - "theme": path.resolve(__dirname, "../theme"), + 'theme': path.resolve(__dirname, '../theme'), // Links in template (null: default, false: remove, string: new value) - "links": { + 'links': { // Custom links at top of sidebar - "sidebar": { - //"Custom link name": "https://customlink.com" + 'sidebar': { + // 'Custom link name': 'https://customlink.com' }, // Sharing links - "sharing": { - "google": null, - "facebook": null, - "twitter": null, - "weibo": null, - "all": null + 'sharing': { + 'google': null, + 'facebook': null, + 'twitter': null, + 'weibo': null, + 'all': null } }, // Options for PDF generation - "pdf": { + 'pdf': { // Add toc at the end of the file - "toc": true, + 'toc': true, // Add page numbers to the bottom of every page - "pageNumbers": false, + 'pageNumbers': false, // Font size for the file content - "fontSize": 12, + 'fontSize': 12, // Paper size for the pdf // Choices are [u’a0’, u’a1’, u’a2’, u’a3’, u’a4’, u’a5’, u’a6’, u’b0’, u’b1’, u’b2’, u’b3’, u’b4’, u’b5’, u’b6’, u’legal’, u’letter’] - "paperSize": "a4", + 'paperSize': 'a4', // How to mark detected chapters. - // Choices are “pagebreak”, “rule”, "both" or “none”. - "chapterMark" : "pagebreak", + // Choices are “pagebreak”, “rule”, 'both' or “none”. + 'chapterMark' : 'pagebreak', // An XPath expression. Page breaks are inserted before the specified elements. - // To disable use the expression: "/" - "pageBreaksBefore": "/", + // To disable use the expression: '/' + 'pageBreaksBefore': '/', // Margin (in pts) // Note: 72 pts equals 1 inch - "margin": { - "right": 62, - "left": 62, - "top": 56, - "bottom": 56 + 'margin': { + 'right': 62, + 'left': 62, + 'top': 56, + 'bottom': 56 }, - //Header HTML template. Available variables: _PAGENUM_, _TITLE_, _AUTHOR_ and _SECTION_. - "headerTemplate": "", + // Header HTML template. Available variables: _PAGENUM_, _TITLE_, _AUTHOR_ and _SECTION_. + 'headerTemplate': '', - //Footer HTML template. Available variables: _PAGENUM_, _TITLE_, _AUTHOR_ and _SECTION_. - "footerTemplate": "" + // Footer HTML template. Available variables: _PAGENUM_, _TITLE_, _AUTHOR_ and _SECTION_. + 'footerTemplate': '' } }; diff --git a/lib/generators/website.js b/lib/generators/website.js index 4bde473..e1a3cce 100644 --- a/lib/generators/website.js +++ b/lib/generators/website.js @@ -112,7 +112,6 @@ Generator.prototype.finish = function() { return this.copyAssets() .then(this.copyCover) .then(this.writeGlossary) - .then(this.writeSearchIndex) .then(this.writeLangsIndex); }; @@ -167,14 +166,6 @@ Generator.prototype.writeGlossary = function() { return this._writeTemplate(this.templates.glossary, {}, path.join(this.options.output, "GLOSSARY.html")); }; -// Write the search index -Generator.prototype.writeSearchIndex = function() { - return fs.writeFile( - path.join(this.options.output, "search_index.json"), - JSON.stringify(this.book.searchIndex) - ); -}; - // Convert a page into a normalized data set Generator.prototype.normalizePage = function(page) { var that = this; diff --git a/lib/index.js b/lib/index.js index 89d5d3c..5a93a54 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,50 +1,56 @@ -var Q = require("q"); -var _ = require("lodash"); -var path = require("path"); -var tinylr = require("tiny-lr"); -var color = require("bash-color"); - -var Book = require("./book"); -var Server = require("./utils/server"); -var stringUtils = require("./utils/string"); -var watch = require("./utils/watch"); -var logger = require("./utils/logger"); +/*eslint no-console: 0*/ + +var Q = require('q'); +var _ = require('lodash'); +var path = require('path'); +var tinylr = require('tiny-lr'); +var color = require('bash-color'); + +var Book = require('./book'); +var initBook = require('./init'); +var Server = require('./utils/server'); +var stringUtils = require('./utils/string'); +var watch = require('./utils/watch'); +var logger = require('./utils/logger'); var LOG_OPTION = { - name: "log", - description: "Minimum log level to display", + name: 'log', + description: 'Minimum log level to display', values: _.chain(logger.LEVELS).keys().map(stringUtils.toLowerCase).value(), - defaults: "info" + defaults: 'info' }; var FORMAT_OPTION = { - name: "format", - description: "Format to build to", - values: ["website", "json", "ebook"], - defaults: "website" + name: 'format', + description: 'Format to build to', + values: ['website', 'json', 'ebook'], + defaults: 'website' }; +// Export init to gitbook library +Book.init = initBook; + module.exports = { Book: Book, LOG_LEVELS: logger.LEVELS, commands: _.flatten([ { - name: "build [book] [output]", - description: "build a book", + name: 'build [book] [output]', + description: 'build a book', options: [ FORMAT_OPTION, LOG_OPTION ], exec: function(args, kwargs) { var input = args[0] || process.cwd(); - var output = args[1] || path.join(input, "_book"); + var output = args[1] || path.join(input, '_book'); var book = new Book(input, _.extend({}, { - "config": { - "output": output + 'config': { + 'output': output }, - "logLevel": kwargs.log + 'logLevel': kwargs.log })); return book.parse() @@ -52,16 +58,16 @@ module.exports = { return book.generate(kwargs.format); }) .then(function(){ - console.log(""); - console.log(color.green("Done, without error")); + console.log(''); + console.log(color.green('Done, without error')); }); } }, - _.map(["pdf", "epub", "mobi"], function(ebookType) { + _.map(['pdf', 'epub', 'mobi'], function(ebookType) { return { - name: ebookType+" [book] [output]", - description: "build a book to "+ebookType, + name: ebookType+' [book] [output]', + description: 'build a book to '+ebookType, options: [ LOG_OPTION ], @@ -70,7 +76,7 @@ module.exports = { var output = args[1]; var book = new Book(input, _.extend({}, { - "logLevel": kwargs.log + 'logLevel': kwargs.log })); return book.parse() @@ -80,30 +86,30 @@ module.exports = { }); }) .then(function(){ - console.log(""); - console.log(color.green("Done, without error")); + console.log(''); + console.log(color.green('Done, without error')); }); } }; }), { - name: "serve [book]", - description: "Build then serve a gitbook from a directory", + name: 'serve [book]', + description: 'Build then serve a gitbook from a directory', options: [ { - name: "port", - description: "Port for server to listen on", + name: 'port', + description: 'Port for server to listen on', defaults: 4000 }, { - name: "lrport", - description: "Port for livereload server to listen on", + name: 'lrport', + description: 'Port for livereload server to listen on', defaults: 35729 }, { - name: "watch", - description: "Enable/disable file watcher", + name: 'watch', + description: 'Enable/disable file watcher', defaults: true }, FORMAT_OPTION, @@ -118,15 +124,15 @@ module.exports = { var lrPath; var generate = function() { - if (server.isRunning()) console.log("Stopping server"); + if (server.isRunning()) console.log('Stopping server'); return server.stop() .then(function() { var book = new Book(input, _.extend({}, { - "config": { - "defaultsPlugins": ["livereload"] + 'config': { + 'defaultsPlugins': ['livereload'] }, - "logLevel": kwargs.log + 'logLevel': kwargs.log })); return book.parse() @@ -137,10 +143,10 @@ module.exports = { }) .then(function(book) { console.log(); - console.log("Starting server ..."); + console.log('Starting server ...'); return server.start(book.options.output, kwargs.port) .then(function() { - console.log("Serving book on http://localhost:"+kwargs.port); + console.log('Serving book on http://localhost:'+kwargs.port); if (lrPath) { // trigger livereload @@ -157,8 +163,8 @@ module.exports = { .then(function(filepath) { // set livereload path lrPath = filepath; - console.log("Restart after change in file", filepath); - console.log(""); + console.log('Restart after change in file', filepath); + console.log(''); return generate(); }); }); @@ -167,17 +173,17 @@ module.exports = { return Q.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(""); + console.log('Live reload server started on port:', kwargs.lrport); + console.log('Press CTRL+C to quit ...'); + console.log(''); return generate(); }); } }, { - name: "install [book]", - description: "install plugins dependencies", + name: 'install [book]', + description: 'install plugins dependencies', exec: function(args) { var input = args[0] || process.cwd(); @@ -188,20 +194,20 @@ module.exports = { return book.plugins.install(); }) .then(function(){ - console.log(""); - console.log(color.green("Done, without error")); + console.log(''); + console.log(color.green('Done, without error')); }); } }, { - name: "init [directory]", - description: "create files and folders based on contents of SUMMARY.md", + name: 'init [directory]', + description: 'create files and folders based on contents of SUMMARY.md', exec: function(args) { - return Book.init(args[0] || process.cwd()) + return initBook(args[0] || process.cwd()) .then(function(){ - console.log(""); - console.log(color.green("Done, without error")); + console.log(''); + console.log(color.green('Done, without error')); }); } } diff --git a/lib/init.js b/lib/init.js new file mode 100644 index 0000000..2fc8016 --- /dev/null +++ b/lib/init.js @@ -0,0 +1,83 @@ +var _ = require('lodash'); +var Q = require('q'); +var path = require('path'); + +var Book = require('./book'); +var fs = require('./utils/fs'); + +// Initialize folder structure for a book +// Read SUMMARY to created the right chapter +function initBook(root, opts) { + var book = new Book(root, opts); + var extensionToUse = '.md'; + + var chaptersPaths = function(chapters) { + return _.reduce(chapters || [], function(accu, chapter) { + var o = { + title: chapter.title + }; + if (chapter.path) o.path = chapter.path; + + return accu.concat( + [o].concat(chaptersPaths(chapter.articles)) + ); + }, []); + }; + + book.log.info.ln('init book at', root); + return fs.mkdirp(root) + .then(function() { + book.log.info.ln('detect structure from SUMMARY (if it exists)'); + return book.parseSummary(); + }) + .fail(function() { + return Q(); + }) + .then(function() { + var summary = book.summaryFile || 'SUMMARY.md'; + var chapters = book.summary.chapters || []; + extensionToUse = path.extname(summary); + + if (chapters.length === 0) { + chapters = [ + { + title: 'Summary', + path: 'SUMMARY'+extensionToUse + }, + { + title: 'Introduction', + path: 'README'+extensionToUse + } + ]; + } + + return Q(chaptersPaths(chapters)); + }) + .then(function(chapters) { + // Create files that don't exist + return Q.all(_.map(chapters, function(chapter) { + if (!chapter.path) return Q(); + var absolutePath = path.resolve(book.root, chapter.path); + + return fs.exists(absolutePath) + .then(function(exists) { + if(exists) { + book.log.info.ln('found', chapter.path); + return; + } else { + book.log.info.ln('create', chapter.path); + } + + return fs.mkdirp(path.dirname(absolutePath)) + .then(function() { + return fs.writeFile(absolutePath, '# '+chapter.title+'\n'); + }); + }); + })); + }) + .then(function() { + book.log.info.ln('initialization is finished'); + }); +} + +module.exports = initBook; diff --git a/lib/pluginslist.js b/lib/pluginslist.js index 80e1d3e..e4594d6 100644 --- a/lib/pluginslist.js +++ b/lib/pluginslist.js @@ -1,14 +1,14 @@ -var _ = require("lodash"); -var Q = require("q"); -var npmi = require("npmi"); -var npm = require("npm"); -var semver = require("semver"); +var _ = require('lodash'); +var Q = require('q'); +var npmi = require('npmi'); +var npm = require('npm'); +var semver = require('semver'); -var Plugin = require("./plugin"); -var pkg = require("../package.json"); +var Plugin = require('./plugin'); +var pkg = require('../package.json'); var initNPM = _.memoize(function() { - return Q.nfcall(npm.load, { silent: true, loglevel: "silent" }); + return Q.nfcall(npm.load, { silent: true, loglevel: 'silent' }); }); @@ -23,7 +23,7 @@ var PluginsList = function(book, plugins) { this.failed = []; // Namespaces - this.namespaces = _.chain(["website", "ebook"]) + this.namespaces = _.chain(['website', 'ebook']) .map(function(namespace) { return [ namespace, @@ -66,7 +66,7 @@ PluginsList.prototype.load = function(plugin) { if (_.isObject(plugin) && !(plugin instanceof Plugin)) plugin = plugin.name; if (_.isString(plugin)) plugin = new Plugin(this.book, plugin); - that.log.info("load plugin", plugin.name, "...."); + that.log.info('load plugin', plugin.name, '....'); if (!plugin.isValid()) { that.log.info.fail(); that.failed.push(plugin.name); @@ -135,7 +135,7 @@ PluginsList.prototype.html = function(namespace, tag, context, options) { var htmlSnippets = this.namespaces[namespace].html[tag]; return _.map(htmlSnippets || [], function(code) { return code.call(context, options); - }).join("\n"); + }).join('\n'); }; // Return a resources map for a namespace @@ -153,10 +153,10 @@ PluginsList.prototype.install = function() { }); // Install plugins one by one - that.book.log.info.ln(plugins.length+" plugins to install"); + that.book.log.info.ln(plugins.length+' plugins to install'); return _.reduce(plugins, function(prev, plugin) { return prev.then(function() { - var fullname = "gitbook-plugin-"+plugin.name; + var fullname = 'gitbook-plugin-'+plugin.name; return Q() @@ -164,10 +164,10 @@ PluginsList.prototype.install = function() { .then(function() { if (plugin.version) return plugin.version; - that.book.log.info.ln("No version specified, resolve plugin", plugin.name); + that.book.log.info.ln('No version specified, resolve plugin', plugin.name); return initNPM() .then(function() { - return Q.nfcall(npm.commands.view, [fullname+"@*", "engines"], true); + return Q.nfcall(npm.commands.view, [fullname+'@*', 'engines'], true); }) .then(function(versions) { return _.chain(versions) @@ -184,7 +184,7 @@ PluginsList.prototype.install = function() { .sort(function(v1, v2) { return semver.lt(v1.version, v2.version)? 1 : -1; }) - .pluck("version") + .pluck('version') .first() .value(); }); @@ -193,23 +193,23 @@ PluginsList.prototype.install = function() { // Install the plugin with the resolved version .then(function(version) { if (!version) { - throw "Found no satisfactory version for plugin "+plugin.name; + throw 'Found no satisfactory version for plugin '+plugin.name; } - that.book.log.info.ln("install plugin", plugin.name, "from npm ("+fullname+") with version", version); + that.book.log.info.ln('install plugin', plugin.name, 'from npm ('+fullname+') with version', version); return Q.nfcall(npmi, { - "name": fullname, - "version": version, - "path": that.book.root, - "npmLoad": { - "loglevel": "silent", - "loaded": true, - "prefix": that.book.root + 'name': fullname, + 'version': version, + 'path': that.book.root, + 'npmLoad': { + 'loglevel': 'silent', + 'loaded': true, + 'prefix': that.book.root } }); }) .then(function() { - that.book.log.info.ok("plugin", plugin.name, "installed with success"); + that.book.log.info.ok('plugin', plugin.name, 'installed with success'); }); }); }, Q()); diff --git a/lib/utils/page.js b/lib/utils/page.js index 2c57421..8adce8f 100644 --- a/lib/utils/page.js +++ b/lib/utils/page.js @@ -1,18 +1,18 @@ -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 links = require("./links"); -var imgUtils = require("./images"); -var fs = require("./fs"); -var batch = require("./batch"); - -var parsableExtensions = require("gitbook-parsers").extensions; +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 links = require('./links'); +var imgUtils = require('./images'); +var fs = require('./fs'); +var batch = require('./batch'); + +var parsableExtensions = require('gitbook-parsers').extensions; // Render a cheerio dom as html var renderDom = function($, dom, options) { @@ -59,7 +59,7 @@ function replaceText($, el, search, replace, text_only ) { // robust way. $(node).before( new_val ); - // Don"t remove the node yet, or the loop will lose its place. + // 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 @@ -79,7 +79,7 @@ function replaceText($, el, search, replace, text_only ) { } function pregQuote( str ) { - return (str+"").replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1"); + return (str+'').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, '\\$1'); } @@ -101,23 +101,23 @@ function normalizeHtml(src, options) { // Find svg images to extract and process if (options.convertImages) { - $("svg").each(function() { + $('svg').each(function() { var content = renderDom($, $(this)); - var svgId = _.uniqueId("svg"); - var dest = svgId+".svg"; + var svgId = _.uniqueId('svg'); + var dest = svgId+'.svg'; // Generate filename - dest = "/"+fs.getUniqueFilename(outputRoot, dest); + dest = '/'+fs.getUniqueFilename(outputRoot, dest); - svgContent[dest] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+content; - $(this).replaceWith($("<img>").attr("src", dest)); + svgContent[dest] = '<?xml version="1.0" encoding="UTF-8"?>'+content; + $(this).replaceWith($('<img>').attr('src', dest)); }); } // Find images to normalize - $("img").each(function() { + $('img').each(function() { var origin; - var src = $(this).attr("src"); + var src = $(this).attr('src'); if (!src) return; var isExternal = links.isExternal(src); @@ -132,13 +132,13 @@ function normalizeHtml(src, options) { // If image is external and ebook, then downlaod the images if (isExternal) { origin = src; - src = "/"+crc.crc32(origin).toString(16)+path.extname(origin); + src = '/'+crc.crc32(origin).toString(16)+path.extname(origin); src = links.toAbsolute(src, options.base, options.output); isExternal = false; } var ext = path.extname(src); - var srcAbs = links.join("/", options.base, src); + var srcAbs = links.join('/', options.base, src); // Test image extension if (_.contains(imgUtils.INVALID, ext)) { @@ -147,29 +147,29 @@ function normalizeHtml(src, options) { src = imgConversionCache[outputRoot][srcAbs]; } else { // Not converted yet - var dest = ""; + var dest = ''; // Replace extension - dest = links.join(path.dirname(srcAbs), path.basename(srcAbs, ext)+".png"); - dest = dest[0] == "/"? dest.slice(1) : dest; + 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 + // 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); + options.book.log.debug.ln('detect invalid image (will be converted to png):', srcAbs); // Add to cache - imgConversionCache[outputRoot][srcAbs] = "/"+dest; + imgConversionCache[outputRoot][srcAbs] = '/'+dest; // Push to convert toConvert.push({ origin: origin, content: svgContent[srcAbs], - source: isExternal? srcAbs : path.join("./", srcAbs), - dest: path.join("./", dest) + source: isExternal? srcAbs : path.join('./', srcAbs), + dest: path.join('./', dest) }); - src = links.join("/", dest); + src = links.join('/', dest); } // Reset as relative to output @@ -180,17 +180,17 @@ function normalizeHtml(src, options) { // Need to downlaod image toConvert.push({ origin: origin, - source: path.join("./", srcAbs) + source: path.join('./', srcAbs) }); } } - $(this).attr("src", src); + $(this).attr('src', src); }); // Normalize links - $("a").each(function() { - var href = $(this).attr("href"); + $('a').each(function() { + var href = $(this).attr('href'); if (!href) return; if (links.isAnchor(href)) { @@ -198,7 +198,7 @@ function normalizeHtml(src, options) { } else if (links.isRelative(href)) { var parts = url.parse(href); var absolutePath = links.join(options.base, parts.pathname); - var anchor = parts.hash || ""; + var anchor = parts.hash || ''; // If is in navigation relative: transform as content @@ -209,33 +209,33 @@ function normalizeHtml(src, options) { // 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+"\""); + _.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; + href = links.toAbsolute('/'+absolutePath, options.base, options.output)+anchor; } else { // External links - $(this).attr("target", "_blank"); + $(this).attr('target', '_blank'); } // Transform extension - $(this).attr("href", href); + $(this).attr('href', href); }); // Highlight code blocks - $("code").each(function() { + $('code').each(function() { // Normalize language var lang = _.chain( - ($(this).attr("class") || "").split(" ") + ($(this).attr('class') || '').split(' ') ) .map(function(cl) { // Markdown - if (cl.search("lang-") === 0) return cl.slice("lang-".length); + if (cl.search('lang-') === 0) return cl.slice('lang-'.length); // Asciidoc - if (cl.search("language-") === 0) return cl.slice("language-".length); + if (cl.search('language-') === 0) return cl.slice('language-'.length); return null; }) @@ -244,7 +244,7 @@ function normalizeHtml(src, options) { .value(); var source = $(this).text(); - var blk = options.book.template.applyBlock("code", { + var blk = options.book.template.applyBlock('code', { body: source, kwargs: { language: lang @@ -261,12 +261,12 @@ function normalizeHtml(src, options) { }); _.each(glossary, function(term) { - var r = new RegExp( "\\b(" + pregQuote(term.name.toLowerCase()) + ")\\b" , "gi" ); + var r = new RegExp( '\\b(' + pregQuote(term.name.toLowerCase()) + ')\\b' , 'gi' ); var includedInFiles = false; - $("*").each(function() { + $('*').each(function() { // Ignore codeblocks - if (_.contains(["code", "pre", "a"], this.name.toLowerCase())) return; + if (_.contains(['code', 'pre', 'a'], this.name.toLowerCase())) return; replaceText($, this, r, function(match) { // Add to files index in glossary @@ -275,7 +275,7 @@ function normalizeHtml(src, options) { 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 '<a href=\''+links.toAbsolute('/GLOSSARY.html', options.base, options.output) + '#' + term.id+'\' class=\'glossary-term\' title=\''+_.escape(term.description)+'\'>'+match+'</a>'; }); }); }); @@ -291,7 +291,7 @@ function convertImages(images, options) { if (!options.convertImages) return Q(); var downloaded = []; - options.book.log.debug.ln("convert ", images.length, "images to png"); + options.book.log.debug.ln('convert ', images.length, 'images to png'); return batch.execEach(images, { max: 100, @@ -303,13 +303,13 @@ function convertImages(images, options) { // 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, "..."); + 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; + err.message = 'Fail downloading '+image.origin+': '+err.message; throw err; }); }) @@ -324,13 +324,13 @@ function convertImages(images, options) { .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, "..."); + 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"); + options.book.log.debug.ok(images.length+' images converted with success'); }); } @@ -344,16 +344,16 @@ function normalizePage(sections, options) { convertImages: false, // Current file path - input: ".", + input: '.', // Navigation to use to transform path navigation: {}, // Directory parent of the file currently in rendering process - base: "./", + base: './', // Directory parent from the html output - output: "./", + output: './', // Glossary terms glossary: [] @@ -363,7 +363,7 @@ function normalizePage(sections, options) { var toConvert = []; sections = _.map(sections, function(section) { - if (section.type != "normal") return section; + if (section.type != 'normal') return section; var out = normalizeHtml(section.content, options); @@ -374,27 +374,13 @@ function normalizePage(sections, options) { return Q() .then(function() { - toConvert = _.uniq(toConvert, "source"); + toConvert = _.uniq(toConvert, 'source'); return convertImages(toConvert, options); }) .thenResolve(sections); } -// Extract text from sections -function extractText(sections) { - return _.reduce(sections, function(prev, section) { - if (section.type != "normal") return prev; - - var $ = cheerio.load(section.content); - $("*").each(function() { - prev = prev+" "+$(this).text(); - }); - - return prev; - }, ""); -} module.exports = { - normalize: normalizePage, - extractText: extractText + normalize: normalizePage }; |