diff options
author | Samy Pesse <samypesse@gmail.com> | 2016-02-11 21:44:38 +0100 |
---|---|---|
committer | Samy Pesse <samypesse@gmail.com> | 2016-02-11 21:44:38 +0100 |
commit | 669f3b39849890c48171d807225cd6eaa3c9086b (patch) | |
tree | bc07fefc4e13ac8f737174166ac1d19512379298 | |
parent | e7eed2abbe91fa44bd071819123bd9ea04d1702a (diff) | |
download | gitbook-669f3b39849890c48171d807225cd6eaa3c9086b.zip gitbook-669f3b39849890c48171d807225cd6eaa3c9086b.tar.gz gitbook-669f3b39849890c48171d807225cd6eaa3c9086b.tar.bz2 |
Add base for normalizing html
-rw-r--r-- | lib/book.js | 2 | ||||
-rw-r--r-- | lib/generators/website/index.js (renamed from lib/generators/website.js) | 12 | ||||
-rw-r--r-- | lib/generators/website/theme.js | 6 | ||||
-rw-r--r-- | lib/page/html.js | 57 | ||||
-rw-r--r-- | lib/page/index.js (renamed from lib/backbone/page.js) | 23 | ||||
-rw-r--r-- | lib/utils/command.js | 27 | ||||
-rw-r--r-- | lib/utils/images.js | 27 | ||||
-rw-r--r-- | lib/utils/promise.js | 12 |
8 files changed, 156 insertions, 10 deletions
diff --git a/lib/book.js b/lib/book.js index 914b48a..0f73135 100644 --- a/lib/book.js +++ b/lib/book.js @@ -9,7 +9,7 @@ var Readme = require('./backbone/readme'); var Glossary = require('./backbone/glossary'); var Summary = require('./backbone/summary'); var Langs = require('./backbone/langs'); -var Page = require('./backbone/page'); +var Page = require('./page'); var TemplateEngine = require('./template'); var pathUtil = require('./utils/path'); var error = require('./utils/error'); diff --git a/lib/generators/website.js b/lib/generators/website/index.js index a2c3311..f474cbb 100644 --- a/lib/generators/website.js +++ b/lib/generators/website/index.js @@ -1,5 +1,5 @@ var util = require('util'); -var Generator = require('./base'); +var Generator = require('../base'); function WebsiteGenerator() { Generator.apply(this, arguments); @@ -8,12 +8,10 @@ util.inherits(WebsiteGenerator, Generator); // Copy an asset file WebsiteGenerator.prototype.writeAsset = function(filename) { - var that = this; - - return that.book.readFile(filename) - .then(function(buf) { - return that.output.writeFile(filename, buf); - }); + return this.output.copyFile( + this.book.resolve(filename), + filename + ); }; // Write a page (parsable file) diff --git a/lib/generators/website/theme.js b/lib/generators/website/theme.js new file mode 100644 index 0000000..1cc2891 --- /dev/null +++ b/lib/generators/website/theme.js @@ -0,0 +1,6 @@ + +function Theme() { + +} + +module.exports = Theme; diff --git a/lib/page/html.js b/lib/page/html.js new file mode 100644 index 0000000..f828d11 --- /dev/null +++ b/lib/page/html.js @@ -0,0 +1,57 @@ +var _ = require('lodash'); +var cheerio = require('cheerio'); +var domSerializer = require('dom-serializer'); +var slug = require('github-slugid'); + +var Promise = require('../utils/promise'); + +// 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 HTMLPipeline(htmlString, opts) { + _.bindAll(this); + + this.opts = _.defaults(opts || {}, { + convertImages: true + }); + + this.$ = cheerio.load(htmlString, { + // We should parse html without trying to normalize too much + xmlMode: false, + + // SVG need some attributes to use uppercases + lowerCaseAttributeNames: false, + lowerCaseTags: false + }); +} + +// Add ID to headings +HTMLPipeline.prototype.addHeadingIDs = function() { + var that = this; + + this.$('h1,h2,h3,h4,h5,h6').each(function() { + // Already has an ID? + if (that.$(this).attr('id')) return; + + that.$(this).attr('id', slug(that.$(this).text())); + }); +}; + +// Write content to the pipeline +HTMLPipeline.prototype.output = function() { + var that = this; + + return Promise() + .then(this.addHeadingIDs) + .then(function() { + return renderDOM(that.$); + }); +}; + +module.exports = HTMLPipeline; diff --git a/lib/backbone/page.js b/lib/page/index.js index 94812d9..8f8819c 100644 --- a/lib/backbone/page.js +++ b/lib/page/index.js @@ -3,6 +3,8 @@ var path = require('path'); var parsers = require('gitbook-parsers'); var error = require('../utils/error'); +var Promise = require('../utils/promise'); +var HTMLPipeline = require('./html'); /* A page represent a parsable file in the book (Markdown, Asciidoc, etc) @@ -63,9 +65,14 @@ Page.prototype.read = function() { }; // Parse the page and return its content -Page.prototype.parse = function() { +Page.prototype.parse = function(opts) { var that = this; + opts = _.defaults(opts || {}, { + + }); + + this.log.debug.ln('start parsing file', this.path); return this.read() @@ -93,6 +100,20 @@ Page.prototype.parse = function() { .then(function() { return that.parser.page(that.content) .then(that.update); + }) + + // Normalize HTML output + .then(function() { + return Promise.map(that.content.sections, function(section) { + var pipeline = new HTMLPipeline(section.content, opts); + + return pipeline.output() + .then(function(content) { + return { + content: content + }; + }); + }); }); }; diff --git a/lib/utils/command.js b/lib/utils/command.js index f395fa1..4269d6c 100644 --- a/lib/utils/command.js +++ b/lib/utils/command.js @@ -13,7 +13,32 @@ function exec(command, options) { return Promise.nfcall(childProcess.exec, command, options); } +// Spawn an executable +function spawn(command, args, options) { + if (!isAvailable) { + return Promise.reject(new Error('Command execution is not possible on this platform')); + } + + var d = Promise.deferred(); + var child = childProcess.spawn(command, args, options); + + child.on('error', function(error) { + return d.reject(error); + }); + + child.on('close', function(code) { + if (code === 0) { + d.resolve(); + } else { + d.reject(new Error('Error with command "'+command+'"')); + } + }); + + return d.promise; +} + module.exports = { isAvailable: isAvailable, - exec: exec + exec: exec, + spawn: spawn }; diff --git a/lib/utils/images.js b/lib/utils/images.js new file mode 100644 index 0000000..3ba0f1f --- /dev/null +++ b/lib/utils/images.js @@ -0,0 +1,27 @@ +var fs = require('fs'); + +var Promise = require('./promise'); +var command = require('./command'); +var error = require('./error'); + +// Convert a svg file to a pmg +function convertSVGToPNG(source, dest, options) { + if (!command.isAvailable) return Promise.reject(new Error('Could not convert SVG in this platform')); + if (!fs.existsSync(source)) return Promise.reject(new error.FileNotFoundError({ filename: source })); + + return command.spawn('svgexport', [source, dest]) + .fail(function(err) { + if (err.code == 'ENOENT') err = new Error('Need to install "svgexport" using "npm install svgexport -g"'); + throw err; + }) + .then(function() { + if (fs.existsSync(dest)) return; + + throw new Error('Error converting '+source+' into '+dest); + }); +} + +module.exports = { + convertSVGToPNG: convertSVGToPNG, + INVALID: ['.svg'] +};
\ No newline at end of file diff --git a/lib/utils/promise.js b/lib/utils/promise.js index 82f4a60..adcc1c3 100644 --- a/lib/utils/promise.js +++ b/lib/utils/promise.js @@ -32,7 +32,19 @@ function some(arr, iter) { }, Q()); } +// Map an array using an async (promised) iterator +function map(arr, iter) { + return reduce(arr, function(prev, entry, i) { + return Q(iter(entry, i)) + .then(function(out) { + prev.push(out); + return prev; + }); + }, []); +} + module.exports = Q; module.exports.reduce = reduce; +module.exports.map = map; module.exports.serie = serie; module.exports.some = some; |