mirror of
				https://github.com/KevinMidboe/inline-html.git
				synced 2025-10-29 17:40:29 +00:00 
			
		
		
		
	Refactor. Update dependencies. Update tests. Make img plugin async.
This commit is contained in:
		| @@ -3,10 +3,7 @@ | ||||
| Inline local assets referenced in an HTML document. | ||||
|  | ||||
| [](https://www.npmjs.com/package/inline-html) | ||||
| [](https://www.npmjs.com/package/inline-html) | ||||
| [](https://travis-ci.org/panosoft/inline-html) | ||||
| [](https://david-dm.org/panosoft/inline-html) | ||||
| [](https://www.npmjs.com/package/inline-html) | ||||
|  | ||||
| This library parses HTML, embeds the contents of local assets that are referenced within that HTML, and returns a new inlined HTML string. | ||||
|  | ||||
|   | ||||
							
								
								
									
										133
									
								
								lib/css-url.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								lib/css-url.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,133 @@ | ||||
| const datauri = require('datauri'); | ||||
| const isLocalPath = require('is-local-path'); | ||||
| const isTemplateExpression = require('./is-template-expression'); | ||||
| const path = require('path'); | ||||
| const postcss = require('postcss'); | ||||
| const postcssUrl = require('postcss-url'); | ||||
| const R = require('ramda'); | ||||
| const string = require('string'); | ||||
| const url = require('url'); | ||||
|  | ||||
| const collapseWhitespace = str => string(str).collapseWhitespace().toString(); | ||||
| const forEachIndexed = R.addIndex(R.forEach); | ||||
| const format = (path) => url.format(path); | ||||
| const parse = (path) => url.parse(path); | ||||
| const resolve = path.resolve; | ||||
|  | ||||
| const augmentError = (error, filename, files) => { | ||||
| 	if (!error.filename) error.filename = filename; | ||||
| 	error.files = R.uniq(R.concat(files, error.files || [])); | ||||
| 	return error; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Returns url path without query string and hash if present. | ||||
|  * | ||||
|  * @param path | ||||
|  * | ||||
|  * @returns path | ||||
|  */ | ||||
| const cleanUrl = R.pipe( | ||||
| 	parse, | ||||
| 	R.pick(['protocol', 'host', 'pathname']), | ||||
| 	format, | ||||
| 	decodeURI | ||||
| ); | ||||
| /** | ||||
|  * Convert local url data type paths to datauris. | ||||
|  * | ||||
|  * @param css | ||||
|  * @param filename | ||||
|  * @returns {{css: (css|any), files: Array}} | ||||
|  */ | ||||
| const inlineUrl = R.curry((filename, css) => { | ||||
| 	const basePath = path.dirname(filename); | ||||
| 	var files = []; | ||||
| 	const inline = url => { | ||||
| 		try { | ||||
| 			if (isLocalPath(url) && !isTemplateExpression(url)) { | ||||
| 				url = cleanUrl(url); | ||||
| 				url = resolve(basePath, url); | ||||
| 				files = R.append(url, files); | ||||
| 				url = datauri(url); | ||||
| 			} | ||||
| 			return url; | ||||
| 		} | ||||
| 		catch (error) { throw augmentError(error, filename, files); } | ||||
| 	}; | ||||
| 	css = postcss() | ||||
| 		.use(postcssUrl({ url: inline })) | ||||
| 		.process(css) | ||||
| 		.css; | ||||
| 	files = R.uniq(files); | ||||
| 	return { css, files }; | ||||
| }); | ||||
|  | ||||
| const inlineStyles = ($, filename) => { | ||||
| 	var files = []; | ||||
| 	try { | ||||
| 		const styles = $('style') | ||||
| 			.toArray(); | ||||
|  | ||||
| 		const contents = R.map(style => { | ||||
| 			const css = $(style).html(); | ||||
| 			const result = inlineUrl(filename, css); | ||||
| 			files = R.concat(files, result.files); | ||||
| 			return result.css; | ||||
| 		}, styles); | ||||
|  | ||||
| 		forEachIndexed((style, index) => $(style).html(contents[index]), styles); | ||||
|  | ||||
| 		return { $, files }; | ||||
| 	} | ||||
| 	catch (error) { throw augmentError(error, filename, files); } | ||||
| }; | ||||
|  | ||||
| const prefix = 'selector {'; | ||||
| const suffix = '}'; | ||||
| const matchStyle = new RegExp(`^${prefix}\\s*(.*)\\s*${suffix}$`); | ||||
| const wrap = style => `${prefix}${style}${suffix}`; | ||||
| const unwrap = rule => rule.replace(matchStyle, '$1'); | ||||
|  | ||||
| const inlineStyleAttributes = ($, filename) => { | ||||
| 	var files = []; | ||||
| 	try { | ||||
| 		const elements = $('*') | ||||
| 			.filter('[style]') | ||||
| 			.toArray(); | ||||
|  | ||||
| 		const styles = R.map(element => { | ||||
| 			var style = $(element).attr('style'); | ||||
| 			const rule = wrap(style); | ||||
| 			const result = inlineUrl(filename, rule); | ||||
| 			files = R.concat(files, result.files); | ||||
| 			style = R.pipe( collapseWhitespace, unwrap )(result.css); | ||||
| 			return style; | ||||
| 		}, elements); | ||||
|  | ||||
| 		forEachIndexed((element, index) => $(element).attr('style', styles[index]), elements); | ||||
|  | ||||
| 		return { $, files }; | ||||
| 	} | ||||
| 	catch (error) { throw augmentError(error, filename, files); } | ||||
| }; | ||||
|  | ||||
| const inlineCssUrl = function ($, filename) { | ||||
| 	var files = []; | ||||
| 	try { | ||||
| 		var result; | ||||
| 		result = inlineStyles($, filename); | ||||
| 		$ = result.$; | ||||
| 		files = R.concat(files, result.files); | ||||
|  | ||||
| 		result = inlineStyleAttributes($, filename); | ||||
| 		$ = result.$; | ||||
| 		files = R.concat(files, result.files); | ||||
|  | ||||
| 		files = R.uniq(files); | ||||
| 		return { $, files }; | ||||
| 	} | ||||
| 	catch (error) { throw augmentError(error, filename, files); } | ||||
| }; | ||||
|  | ||||
| module.exports = inlineCssUrl; | ||||
							
								
								
									
										48
									
								
								lib/img.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								lib/img.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| const co = require('co'); | ||||
| const datauri = require('datauri').promises; | ||||
| const isLocalPath = require('is-local-path'); | ||||
| const isTemplateExpression = require('./is-template-expression'); | ||||
| const path = require('path'); | ||||
| const R = require('ramda'); | ||||
|  | ||||
| const forEachIndexed = R.addIndex(R.forEach); | ||||
| const resolve = R.curry((a,b) => path.resolve(a,b)); | ||||
|  | ||||
| /** | ||||
|  * Inline sourced image files | ||||
|  * | ||||
|  * @param {Object} $ | ||||
|  * 	Parsed HTML source to inline | ||||
|  * @param {String} filename | ||||
|  * 	Filename used to resolve relative sources being inlined | ||||
|  */ | ||||
| const inlineImg = co.wrap(function * ($, filename) { | ||||
| 	var files; | ||||
| 	const basedir = path.dirname(filename); | ||||
| 	const getAttr = R.curry((attr, element) => $(element).attr(attr)); | ||||
| 	const setAttr = R.curry((attr, element, value) => $(element).attr(attr, value)); | ||||
| 	const getFilename = R.pipe(getAttr('src'), resolve(basedir)); | ||||
| 	try { | ||||
| 		const images = $('img') | ||||
| 			.filter((index, element) => { | ||||
| 				const source = $(element).attr('src'); | ||||
| 				return isLocalPath(source) && !isTemplateExpression(source); | ||||
| 			}) | ||||
| 			.toArray(); | ||||
|  | ||||
| 		const filenames = R.map(getFilename, images); | ||||
| 		files = R.uniq(filenames); | ||||
| 		const uris = yield R.map(datauri, filenames); | ||||
|  | ||||
| 		forEachIndexed((image, index) => setAttr('src', image, uris[index]), images); | ||||
| 		 | ||||
| 		return { $, files }; | ||||
| 	} | ||||
| 	catch (error) { | ||||
| 		error.filename = filename; | ||||
| 		error.files = files; | ||||
| 		throw error; | ||||
| 	} | ||||
| }); | ||||
|  | ||||
| module.exports = inlineImg; | ||||
							
								
								
									
										59
									
								
								lib/index.js
									
									
									
									
									
								
							
							
						
						
									
										59
									
								
								lib/index.js
									
									
									
									
									
								
							| @@ -1,12 +1,13 @@ | ||||
| var co = require('co'); | ||||
| var fs = require('mz/fs'); | ||||
| var inlineStyle = require('./inline-style'); | ||||
| var inlineImg = require('./inline-img'); | ||||
| var inlineLess = require('./inline-less'); | ||||
| var R = require('ramda'); | ||||
| var Ru = require('@panosoft/ramda-utils'); | ||||
| const cheerio = require('cheerio'); | ||||
| const co = require('co'); | ||||
| const fs = require('mz/fs'); | ||||
| const inlineCssUrl = require('./css-url'); | ||||
| const inlineImg = require('./img'); | ||||
| const inlineLess = require('./link-less'); | ||||
| const R = require('ramda'); | ||||
| const Ru = require('@panosoft/ramda-utils'); | ||||
|  | ||||
| var inlineHtml = {}; | ||||
| var inline = {}; | ||||
| /** | ||||
|  * Embed referenced local assets within and HTML file. | ||||
|  * | ||||
| @@ -15,44 +16,46 @@ var inlineHtml = {}; | ||||
|  * | ||||
|  * @return {Promise} | ||||
|  */ | ||||
| inlineHtml.html = co.wrap(function * (html, options) { | ||||
| inline.html = co.wrap(function * (html, options) { | ||||
| 	options = Ru.defaults({ | ||||
| 		filename: null, | ||||
| 		less: {}, | ||||
| 		verbose: false | ||||
| 	}, options || {}); | ||||
| 	var filename = options.filename; | ||||
|  | ||||
| 	// Embed assets | ||||
| 	const filename = options.filename; | ||||
| 	var files = [filename]; | ||||
| 	try { | ||||
| 		var lessResult = yield inlineLess(html, filename, options.less); | ||||
| 		html = lessResult.html; | ||||
| 		files = R.concat(files, lessResult.files); | ||||
| 		var $ = cheerio.load(html, {decodeEntities: false}); | ||||
|  | ||||
| 		var styleResult = inlineStyle(html, filename); | ||||
| 		html = styleResult.html; | ||||
| 		files = R.concat(files, styleResult.files); | ||||
| 		var result; | ||||
| 		result = yield inlineLess($, filename, options); | ||||
| 		$ = result.$; | ||||
| 		files = R.concat(files, result.files); | ||||
|  | ||||
| 		var imgResult = inlineImg(html, filename); | ||||
| 		html = imgResult.html; | ||||
| 		files = R.concat(files, imgResult.files); | ||||
| 		result = inlineCssUrl($, filename); | ||||
| 		$ = result.$; | ||||
| 		files = R.concat(files, result.files); | ||||
|  | ||||
| 		result = yield inlineImg($, filename); | ||||
| 		$ = result.$; | ||||
| 		files = R.concat(files, result.files); | ||||
|  | ||||
| 		html = $.xml(); | ||||
| 		files = R.uniq(files); | ||||
| 		return (options.verbose ? { html, files } : html); | ||||
| 	} | ||||
| 	catch (error) { | ||||
| 		if (!error.filename) error.filename = filename; | ||||
| 		error.files = R.uniq(R.concat(files, error.files || [])); | ||||
| 		throw error; | ||||
| 	} | ||||
|  | ||||
| 	files = R.uniq(files); | ||||
| 	var result = { html, files }; | ||||
| 	return (options.verbose ? result : result.html); | ||||
| }); | ||||
|  | ||||
| inlineHtml.file = co.wrap(function * (filename, options) { | ||||
| 	var html = yield fs.readFile(filename, 'utf8'); | ||||
| inline.file = co.wrap(function * (filename, options) { | ||||
| 	const html = yield fs.readFile(filename, 'utf8'); | ||||
| 	options = R.merge(options || {}, {filename}); | ||||
| 	return yield inlineHtml.html(html, options); | ||||
| 	return yield inline.html(html, options); | ||||
| }); | ||||
|  | ||||
| module.exports = inlineHtml; | ||||
| module.exports = inline; | ||||
|   | ||||
| @@ -1,61 +0,0 @@ | ||||
| var datauri = require('datauri'); | ||||
| var isLocalPath = require('is-local-path'); | ||||
| var isTemplateExpression = require('./is-template-expression'); | ||||
| var path = require('path'); | ||||
| var postcss = require('postcss'); | ||||
| var postcssUrl = require('postcss-url'); | ||||
| var R = require('ramda'); | ||||
| var url = require('url'); | ||||
|  | ||||
| /** | ||||
|  * Returns url path without query string and hash if present. | ||||
|  * | ||||
|  * @param path | ||||
|  * | ||||
|  * @returns path | ||||
|  */ | ||||
| var clean = function (path) { | ||||
| 	path = url.parse(path); | ||||
| 	path = R.pick(['protocol', 'host', 'pathname'], path); | ||||
| 	path = url.format(path); | ||||
| 	path = decodeURI(path); | ||||
| 	return path; | ||||
| }; | ||||
| /** | ||||
|  * Convert local url data type paths to datauris. | ||||
|  * | ||||
|  * @param css | ||||
|  * @param filename | ||||
|  * @returns {{css: (css|any), files: Array}} | ||||
|  */ | ||||
| var inlineUrl = function (css, filename) { | ||||
| 	var files = []; | ||||
| 	var basePath = path.dirname(filename); | ||||
| 	var result = postcss() | ||||
| 		.use(postcssUrl({ | ||||
| 			url: function (urlPath) { | ||||
| 				if (isLocalPath(urlPath) && !isTemplateExpression(urlPath)) { | ||||
| 					try { | ||||
| 						urlPath = clean(urlPath); | ||||
| 						urlPath = path.resolve(basePath, urlPath); | ||||
| 						files = R.append(urlPath, files); | ||||
| 						urlPath = datauri(urlPath); | ||||
| 					} | ||||
| 					catch (error) { | ||||
| 						error.filename = filename; | ||||
| 						error.files = R.uniq(files); | ||||
| 						throw error; | ||||
| 					} | ||||
| 				} | ||||
| 				return urlPath; | ||||
| 			} | ||||
| 		})) | ||||
| 		.process(css); | ||||
| 	files = R.uniq(files); | ||||
| 	return { | ||||
| 		css: result.css, | ||||
| 		files | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| module.exports = inlineUrl; | ||||
| @@ -1,37 +0,0 @@ | ||||
| var cheerio = require('cheerio'); | ||||
| var datauri = require('datauri'); | ||||
| var isLocalPath = require('is-local-path'); | ||||
| var isTemplateExpression = require('./is-template-expression'); | ||||
| var path = require('path'); | ||||
| var R = require('ramda'); | ||||
|  | ||||
| var inline = function (html, filename) { | ||||
| 	var files = []; | ||||
| 	var basedir = path.dirname(filename); | ||||
| 	var $ = cheerio.load(html, {decodeEntities: false}); | ||||
| 	var $images = $('img').filter((index, element) => { | ||||
| 		var path = $(element).attr('src'); | ||||
| 		return isLocalPath(path) && !isTemplateExpression(path); | ||||
| 	}); | ||||
| 	try { | ||||
| 		$images.each((index, element) => { | ||||
| 			var source = $(element).attr('src'); | ||||
| 			var filename = path.resolve(basedir, source); | ||||
| 			files = R.append(filename, files); | ||||
| 			var uri = datauri(filename); | ||||
| 			$(element).attr('src', uri); | ||||
| 		}); | ||||
| 	} | ||||
| 	catch (error) { | ||||
| 		error.filename = filename; | ||||
| 		error.files = R.uniq(files); | ||||
| 		throw error; | ||||
| 	} | ||||
| 	files = R.uniq(files); | ||||
| 	return { | ||||
| 		html: $.xml(), | ||||
| 		files | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| module.exports = inline; | ||||
| @@ -1,67 +0,0 @@ | ||||
| var co = require('co'); | ||||
| var cheerio = require('cheerio'); | ||||
| var fs = require('mz/fs'); | ||||
| var isLocalPath = require('is-local-path'); | ||||
| var less = require('less'); | ||||
| var path = require('path'); | ||||
| var R = require('ramda'); | ||||
| var Ru = require('@panosoft/ramda-utils'); | ||||
|  | ||||
| var render = co.wrap(function * (filename, options) { | ||||
| 	options = R.merge(options || {}, { filename }); | ||||
| 	var contents = yield fs.readFile(filename, 'utf8'); | ||||
| 	return yield less.render(contents, options); | ||||
| }); | ||||
| /** | ||||
|  * @param {String} html | ||||
|  * 	HTML source to inline | ||||
|  * @param {String} filename | ||||
|  * 	Filename to apply to the HTML source being inlined | ||||
|  * @param {Object} options | ||||
|  * 	LESS compiler options | ||||
|  */ | ||||
| var inlineLess = co.wrap(function * (html, filename, options) { | ||||
| 	options = Ru.defaults({ | ||||
| 		relativeUrls: true | ||||
| 	}, options || {}); | ||||
| 	var basedir = path.dirname(filename); | ||||
|  | ||||
| 	// get links | ||||
| 	var $ = cheerio.load(html, {decodeEntities: false}); | ||||
| 	var $links = $('link[rel="stylesheet/less"]') | ||||
| 		.filter((index, element) => isLocalPath($(element).attr('href'))); | ||||
|  | ||||
| 	// render LESS stylesheets | ||||
| 	var files = []; | ||||
| 	var outputs = []; | ||||
| 	try { | ||||
| 		$links.each((index, element) => { | ||||
| 			var href = $(element).attr('href'); | ||||
| 			var filename = path.resolve(basedir, href); | ||||
| 			files = R.append(filename, files); | ||||
| 			outputs = R.append(render(filename, options), outputs); | ||||
| 		}); | ||||
| 		outputs = yield outputs; | ||||
| 	} | ||||
| 	catch (error) { | ||||
| 		if (!error.filename) error.filename = filename; | ||||
| 		error.files = R.uniq(files); | ||||
| 		throw error; | ||||
| 	} | ||||
|  | ||||
| 	// include imported filenames in files array | ||||
| 	files = R.concat(files, R.flatten(R.map(output => output.imports, outputs))); | ||||
| 	files = R.uniq(files); | ||||
|  | ||||
| 	// replace links | ||||
| 	$links.each((index, element) => { | ||||
| 		var style = $('<style>').html(outputs[index].css); | ||||
| 		$(element).replaceWith(style); | ||||
| 	}); | ||||
|  | ||||
| 	return { | ||||
| 		html: $.xml(), | ||||
| 		files | ||||
| 	}; | ||||
| }); | ||||
| module.exports = inlineLess; | ||||
| @@ -1,54 +0,0 @@ | ||||
| var cheerio = require('cheerio'); | ||||
| var inlineUrl = require('./inline-css-url'); | ||||
| var R = require('ramda'); | ||||
| var string = require('string'); | ||||
|  | ||||
| var prefix = 'element {'; | ||||
| var suffix = '}'; | ||||
| var wrap = function (value) { | ||||
| 	return prefix + value + suffix; | ||||
| }; | ||||
| var unwrap = function (value) { | ||||
| 	var regexp = new RegExp('^' + prefix + '\\s*(.*)\\s*' + suffix + '$'); | ||||
| 	return value.replace(regexp, '$1'); | ||||
| }; | ||||
| var inlineStyle = function (html, filename) { | ||||
| 	var files = []; | ||||
| 	var $ = cheerio.load(html, {decodeEntities: false}); | ||||
|  | ||||
| 	try { | ||||
| 		// style elements | ||||
| 		var $styles = $('style'); | ||||
| 		$styles.each((index, element) => { | ||||
| 			var css = $(element).html(); | ||||
| 			var result = inlineUrl(css, filename); | ||||
| 			files = R.concat(files, result.files); | ||||
| 			$(element).html(result.css); | ||||
| 		}); | ||||
|  | ||||
| 		// style attributes | ||||
| 		var $attributes = $('*').filter('[style]'); | ||||
| 		$attributes.each((index, element) => { | ||||
| 			var css = $(element).attr('style'); | ||||
| 			css = wrap(css); | ||||
| 			var result = inlineUrl(css, filename); | ||||
| 			files = R.concat(files, result.files); | ||||
| 			css = string(result.css).collapseWhitespace().toString(); | ||||
| 			css = unwrap(css); | ||||
| 			$(element).attr('style', css); | ||||
| 		}); | ||||
| 	} | ||||
| 	catch (error) { | ||||
| 		if (!error.filename) error.filename = filename; | ||||
| 		error.files = R.uniq(R.concat(files, error.files || [])); | ||||
| 		throw error; | ||||
| 	} | ||||
|  | ||||
| 	files = R.uniq(files); | ||||
| 	return { | ||||
| 		html: $.xml(), | ||||
| 		files | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| module.exports = inlineStyle; | ||||
| @@ -7,8 +7,6 @@ | ||||
|  * @param {String} path | ||||
|  * @return {Boolean} | ||||
|  */ | ||||
| var isTemplateExpression = function (path) { | ||||
| 	return /^{{.*}}$/.test(path); | ||||
| }; | ||||
| const isTemplateExpression = path => /^{{.*}}$/.test(path); | ||||
|  | ||||
| module.exports = isTemplateExpression; | ||||
|   | ||||
							
								
								
									
										58
									
								
								lib/link-less.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								lib/link-less.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| const co = require('co'); | ||||
| const fs = require('mz/fs'); | ||||
| const isLocalPath = require('is-local-path'); | ||||
| const less = require('less'); | ||||
| const path = require('path'); | ||||
| const R = require('ramda'); | ||||
| const Ru = require('@panosoft/ramda-utils'); | ||||
|  | ||||
| const forEachIndexed = R.addIndex(R.forEach); | ||||
| const resolve = R.curry((a,b) => path.resolve(a,b)); | ||||
|  | ||||
| const render = R.curryN(2, co.wrap(function * (options, filename) { | ||||
| 	options = R.merge(options || {}, { filename }); | ||||
| 	const contents = yield fs.readFile(filename, 'utf8'); | ||||
| 	return yield less.render(contents, options); | ||||
| })); | ||||
| /** | ||||
|  * Inline linked less files | ||||
|  * | ||||
|  * @param {Object} $ | ||||
|  * 	Parsed HTML source to inline | ||||
|  * @param {String} filename | ||||
|  * 	Filename to apply to the HTML source being inlined | ||||
|  * @param {Object} [options] | ||||
|  * @param {Object} [options.less] | ||||
|  * 	LESS compiler options | ||||
|  */ | ||||
| const inlineLess = co.wrap(function * ($, filename, options) { | ||||
| 	options = Ru.defaults({ less: {} }, options || {}); | ||||
| 	options = Ru.defaults({ relativeUrls: true }, options.less); | ||||
| 	var files = []; | ||||
| 	const basedir = path.dirname(filename); | ||||
| 	const getAttr = R.curry((attr, element) => $(element).attr(attr)); | ||||
| 	const getStylesheet = R.pipe(getAttr('href'), resolve(basedir)); | ||||
| 	try { | ||||
| 		const links = $('link[rel="stylesheet/less"]') | ||||
| 			.filter((index, link) => isLocalPath($(link).attr('href'))) | ||||
| 			.toArray(); | ||||
|  | ||||
| 		const stylesheets = R.map(getStylesheet, links); | ||||
| 		files = R.concat(files, stylesheets); | ||||
| 		const outputs = yield R.map(render(options), stylesheets); | ||||
| 		const imports = R.flatten(R.map(R.prop('imports'), outputs)); | ||||
| 		files = R.concat(files, imports); | ||||
| 		const styles = R.map(output => $('<style>').html(output.css), outputs); | ||||
|  | ||||
| 		forEachIndexed((link, index) => $(link).replaceWith(styles[index]), links); | ||||
|  | ||||
| 		files = R.uniq(files); | ||||
| 		return { $, files }; | ||||
| 	} | ||||
| 	catch (error) { | ||||
| 		if (!error.filename) error.filename = filename; | ||||
| 		error.files = R.uniq(files); | ||||
| 		throw error; | ||||
| 	} | ||||
| }); | ||||
| module.exports = inlineLess; | ||||
| @@ -5,21 +5,22 @@ | ||||
|   "repository": "panosoft/inline-html", | ||||
|   "main": "lib/index.js", | ||||
|   "scripts": { | ||||
|     "test": "mocha --harmony_arrow_functions" | ||||
|     "test": "mocha", | ||||
|     "test:debug": "mocha --debug-brk" | ||||
|   }, | ||||
|   "author": "", | ||||
|   "license": "MIT", | ||||
|   "dependencies": { | ||||
|     "@panosoft/ramda-utils": "^0.1.12", | ||||
|     "@panosoft/ramda-utils": "^0.2.0", | ||||
|     "cheerio": "^0.19.0", | ||||
|     "co": "^4.6.0", | ||||
|     "datauri": "^0.8.0", | ||||
|     "is-local-path": "^0.1.0", | ||||
|     "less": "^2.5.1", | ||||
|     "mz": "^2.0.0", | ||||
|     "postcss": "^5.0.0", | ||||
|     "postcss": "^5.0.12", | ||||
|     "postcss-url": "^5.0.0", | ||||
|     "ramda": "^0.17.1", | ||||
|     "ramda": "^0.18.0", | ||||
|     "string": "^3.3.0" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|   | ||||
							
								
								
									
										108
									
								
								test/index.js
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								test/index.js
									
									
									
									
									
								
							| @@ -203,8 +203,60 @@ describe('inline-html', () => { | ||||
| 				} | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('image: include all sources in error.files up until and including invalid source', () => { | ||||
| 			return co(function * () { | ||||
| 				var filename = path.resolve(__dirname, 'index.html'); | ||||
| 				var valid = 'fixtures/file.txt'; | ||||
| 				var invalid = 'missing.png'; | ||||
| 				var resolvedInvalid = path.resolve(path.dirname(filename), invalid); | ||||
| 				var resolvedValid = path.resolve(path.dirname(filename), valid); | ||||
| 				var html = ` | ||||
| 					<img src="${valid}" > | ||||
| 					<img src="${invalid}" > | ||||
| 				`; | ||||
| 				try { | ||||
| 					yield inline.html(html, {filename}); | ||||
| 					throw new Error('No error thrown'); | ||||
| 				} | ||||
| 				catch (error) { | ||||
| 					expect(error).to.have.property('filename').that.equals(filename); | ||||
| 					expect(error).to.have.property('files').that.contains(resolvedValid); | ||||
| 					expect(error).to.have.property('files').that.contains(resolvedInvalid); | ||||
| 				} | ||||
| 			}); | ||||
| 		}); | ||||
| 		// inline-style | ||||
| 		it('throw error when html style attribute syntax invalid', () => { | ||||
| 		it('throw error when style element syntax invalid', () => { | ||||
| 			return co(function * () { | ||||
| 				var filename = path.resolve(__dirname, 'index.html'); | ||||
| 				var html = `<style>div {</style>`; | ||||
| 				try { | ||||
| 					yield inline.html(html, {filename}); | ||||
| 					throw new Error('No error thrown'); | ||||
| 				} | ||||
| 				catch (error) { | ||||
| 					expect(error).to.have.property('filename').that.equals(filename); | ||||
| 					expect(error).to.have.property('files').that.contains(filename); | ||||
| 				} | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('throw error when html style url invalid', () => { | ||||
| 			return co(function * () { | ||||
| 				var filename = path.resolve(__dirname, 'index.html'); | ||||
| 				var url = 'missing.png'; | ||||
| 				var resolvedUrl = path.resolve(path.dirname(filename), url); | ||||
| 				var html = `<style>div { background-image: url('${url}'); }</style>`; | ||||
| 				try { | ||||
| 					yield inline.html(html, {filename}); | ||||
| 					throw new Error('No error thrown'); | ||||
| 				} | ||||
| 				catch (error) { | ||||
| 					expect(error).to.have.property('filename').that.equals(filename); | ||||
| 					expect(error).to.have.property('files').that.contains(resolvedUrl); | ||||
| 				} | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('throw error when style attribute syntax invalid', () => { | ||||
| 			return co(function * () { | ||||
| 				var filename = path.resolve(__dirname, 'index.html'); | ||||
| 				var html = `<div style="background url()"></div>`; | ||||
| @@ -234,33 +286,69 @@ describe('inline-html', () => { | ||||
| 				} | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('throw error when html style syntax invalid', () => { | ||||
| 		it('include valid and invalid paths in error.files when html style url invalid', () => { | ||||
| 			return co(function * () { | ||||
| 				var filename = path.resolve(__dirname, 'index.html'); | ||||
| 				var html = `<style>div {</style>`; | ||||
| 				var validUrl = 'fixtures/file.txt'; | ||||
| 				var invalidUrl = 'missing.png'; | ||||
| 				var resolvedInvalidUrl = path.resolve(path.dirname(filename), invalidUrl); | ||||
| 				var resolvedValidUrl = path.resolve(path.dirname(filename), validUrl); | ||||
| 				var html = ` | ||||
| 					<style>div {background-image: url("${validUrl}");}</style> | ||||
| 					<style>div { background-image: url('${invalidUrl}'); }</style> | ||||
| 				`; | ||||
| 				try { | ||||
| 					yield inline.html(html, {filename}); | ||||
| 					throw new Error('No error thrown'); | ||||
| 				} | ||||
| 				catch (error) { | ||||
| 					expect(error).to.have.property('filename').that.equals(filename); | ||||
| 					expect(error).to.have.property('files').that.contains(filename); | ||||
| 					expect(error).to.have.property('files').that.contains(resolvedValidUrl); | ||||
| 					expect(error).to.have.property('files').that.contains(resolvedInvalidUrl); | ||||
| 				} | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('throw error when html style url invalid', () => { | ||||
| 		it('include valid and invalid paths in error.files when html attribute url invalid', () => { | ||||
| 			return co(function * () { | ||||
| 				var filename = path.resolve(__dirname, 'index.html'); | ||||
| 				var url = 'missing.png'; | ||||
| 				var resolvedUrl = path.resolve(path.dirname(filename), url); | ||||
| 				var html = `<style>div { background-image: url('${url}'); }</style>`; | ||||
| 				var validUrl = 'fixtures/file.txt'; | ||||
| 				var invalidUrl = 'missing.png'; | ||||
| 				var resolvedInvalidUrl = path.resolve(path.dirname(filename), invalidUrl); | ||||
| 				var resolvedValidUrl = path.resolve(path.dirname(filename), validUrl); | ||||
| 				var html = ` | ||||
| 					<div style="background-image: url('${validUrl}')"></div> | ||||
| 					<div style="background-image: url('${invalidUrl}')"></div> | ||||
| 				`; | ||||
| 				try { | ||||
| 					yield inline.html(html, {filename}); | ||||
| 					throw new Error('No error thrown'); | ||||
| 				} | ||||
| 				catch (error) { | ||||
| 					expect(error).to.have.property('filename').that.equals(filename); | ||||
| 					expect(error).to.have.property('files').that.contains(resolvedUrl); | ||||
| 					expect(error).to.have.property('files').that.contains(resolvedValidUrl); | ||||
| 					expect(error).to.have.property('files').that.contains(resolvedInvalidUrl); | ||||
| 				} | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('include valid and invalid paths in error.files when style element valid and html attribute invalid', () => { | ||||
| 			return co(function * () { | ||||
| 				var filename = path.resolve(__dirname, 'index.html'); | ||||
| 				var validUrl = 'fixtures/file.txt'; | ||||
| 				var invalidUrl = 'missing.png'; | ||||
| 				var resolvedInvalidUrl = path.resolve(path.dirname(filename), invalidUrl); | ||||
| 				var resolvedValidUrl = path.resolve(path.dirname(filename), validUrl); | ||||
| 				var html = ` | ||||
| 					<style>div {background-image: url("${validUrl}");}</style> | ||||
| 					<div style="background-image: url('${invalidUrl}')"></div> | ||||
| 				`; | ||||
| 				try { | ||||
| 					yield inline.html(html, {filename}); | ||||
| 					throw new Error('No error thrown'); | ||||
| 				} | ||||
| 				catch (error) { | ||||
| 					expect(error).to.have.property('filename').that.equals(filename); | ||||
| 					expect(error).to.have.property('files').that.contains(resolvedValidUrl); | ||||
| 					expect(error).to.have.property('files').that.contains(resolvedInvalidUrl); | ||||
| 				} | ||||
| 			}); | ||||
| 		}); | ||||
| @@ -317,7 +405,6 @@ describe('inline-html', () => { | ||||
| 			return co(function * () { | ||||
| 				var filename = path.resolve(__dirname, 'fixtures/index.html'); | ||||
| 				var lessBasename = 'invalidUrl.less'; | ||||
| 				var lessFilename = path.resolve(path.dirname(filename), lessBasename); | ||||
| 				var badUrl = path.resolve(path.dirname(filename), 'missing.png'); | ||||
| 				var html = `<link rel="stylesheet/less" href="${lessBasename}">`; | ||||
| 				try { | ||||
| @@ -333,5 +420,4 @@ describe('inline-html', () => { | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
|  | ||||
| }); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user