From 0bd64b1308bb645fd8851f41772f0562d1dd800a Mon Sep 17 00:00:00 2001 From: Alexandre Gigliotti Date: Wed, 26 Aug 2015 10:31:29 -0700 Subject: [PATCH] Added support for html being a string or filename. Added tests. Updated dependencies. Updated docs. --- README.md | 5 +- lib/index.js | 17 ++- package.json | 9 +- test/fixtures/assets/imported.css | 8 -- test/fixtures/assets/person.png | Bin 5836 -> 0 bytes test/fixtures/basic.css | 1 + test/fixtures/basic.less | 1 + test/fixtures/css-url.html | 1 + test/fixtures/file.txt | 1 + test/fixtures/img.html | 1 + test/fixtures/import.less | 2 + test/fixtures/index.html | 25 ----- test/fixtures/main.less | 7 -- test/index.js | 168 ++++++++++++++++++++++++++++-- test/inline-css-url.js | 7 -- test/inline-link-less.js | 10 -- 16 files changed, 191 insertions(+), 72 deletions(-) delete mode 100644 test/fixtures/assets/imported.css delete mode 100644 test/fixtures/assets/person.png create mode 100644 test/fixtures/basic.css create mode 100644 test/fixtures/basic.less create mode 100644 test/fixtures/css-url.html create mode 100644 test/fixtures/file.txt create mode 100644 test/fixtures/img.html create mode 100644 test/fixtures/import.less delete mode 100644 test/fixtures/index.html delete mode 100644 test/fixtures/main.less delete mode 100644 test/inline-css-url.js delete mode 100644 test/inline-link-less.js diff --git a/README.md b/README.md index 23fb6ce..665cae1 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ To create the following `html` string: --- -### inlineHtml ( filename [, options] ) +### inlineHtml ( html [, options] ) Reads an HTML file and embeds referenced local assets into the HTML. @@ -89,8 +89,9 @@ Returns a `Promise` that is fulfilled with an `html` string or an instance of [` __Arguments__ -- `filename` - The filename of the HTML file to be inlined. Relative file paths are resolved relative to the filename directory. +- `html` - An HTML string or a filename of an HTML file to inline. Relative file paths are resolved relative to `options.filename` if a string or the filename's directory if a filename. - `options` + - `filename` - The filename used to resolve relative paths when `html` is a string. If `html` is a string and this option is not provided, relative paths will be resolved relative to the process's current working directory. - `less` - An object containing LESS options to pass to the less compiler. Defaults to `{}`. - `verbose` - A boolean that determines the promises fulfillment value. Supported values are: - `true`: An instance of [`Results`](#Results). diff --git a/lib/index.js b/lib/index.js index 3245be5..dfbf9d1 100644 --- a/lib/index.js +++ b/lib/index.js @@ -6,12 +6,25 @@ var inlineStyle = require('./inline-style'); var inlineImg = require('./inline-img'); var inlineLinkLess = require('./inline-link-less'); -var inline = co.wrap(function * (filename, options) { +var inline = co.wrap(function * (html, options) { options = _.defaults(options || {}, { + filename: null, less: {}, verbose: false }); - var html = yield fs.readFile(filename, 'utf8'); + var filename; + try { + filename = html; + html = yield fs.readFile(filename, 'utf8'); + } + catch (error) { + if (error.code === 'ENOENT') { + filename = options.filename; + } + else { + throw error; + } + } var files = [filename]; // Inline links diff --git a/package.json b/package.json index 33b3d42..1a192d5 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "repository": "panosoft/inline-html", "main": "lib/index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "mocha --harmony_arrow_functions" }, "author": "", "license": "MIT", @@ -17,8 +17,13 @@ "less": "^2.5.1", "lodash": "^3.10.0", "mz": "^2.0.0", - "postcss": "^4.1.16", + "postcss": "^5.0.0", "postcss-url": "^4.0.0", "string": "^3.3.0" + }, + "devDependencies": { + "chai": "^3.2.0", + "chai-as-promised": "^5.1.0", + "mocha": "^2.2.5" } } diff --git a/test/fixtures/assets/imported.css b/test/fixtures/assets/imported.css deleted file mode 100644 index e9ad805..0000000 --- a/test/fixtures/assets/imported.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - border: solid 4px green; -} -#import { - background-image: url('./person.png'); - background-size: contain; - background-repeat: no-repeat; -} \ No newline at end of file diff --git a/test/fixtures/assets/person.png b/test/fixtures/assets/person.png deleted file mode 100644 index ad607a9a40757aa2e0ba75d08670031433e96511..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5836 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 A7ytkO diff --git a/test/fixtures/basic.css b/test/fixtures/basic.css new file mode 100644 index 0000000..76ed3ff --- /dev/null +++ b/test/fixtures/basic.css @@ -0,0 +1 @@ +div { color: blue; } diff --git a/test/fixtures/basic.less b/test/fixtures/basic.less new file mode 100644 index 0000000..76ed3ff --- /dev/null +++ b/test/fixtures/basic.less @@ -0,0 +1 @@ +div { color: blue; } diff --git a/test/fixtures/css-url.html b/test/fixtures/css-url.html new file mode 100644 index 0000000..1c35656 --- /dev/null +++ b/test/fixtures/css-url.html @@ -0,0 +1 @@ + diff --git a/test/fixtures/file.txt b/test/fixtures/file.txt new file mode 100644 index 0000000..90b67dd --- /dev/null +++ b/test/fixtures/file.txt @@ -0,0 +1 @@ +Test. diff --git a/test/fixtures/img.html b/test/fixtures/img.html new file mode 100644 index 0000000..e5b058f --- /dev/null +++ b/test/fixtures/img.html @@ -0,0 +1 @@ + diff --git a/test/fixtures/import.less b/test/fixtures/import.less new file mode 100644 index 0000000..d120e67 --- /dev/null +++ b/test/fixtures/import.less @@ -0,0 +1,2 @@ +@import 'basic.less'; +@import (inline) 'basic.css'; diff --git a/test/fixtures/index.html b/test/fixtures/index.html deleted file mode 100644 index b967eaa..0000000 --- a/test/fixtures/index.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - -
Import
-
Style
-
Attribute
- Image - {{> partial}} - {{helper}} - - \ No newline at end of file diff --git a/test/fixtures/main.less b/test/fixtures/main.less deleted file mode 100644 index aead599..0000000 --- a/test/fixtures/main.less +++ /dev/null @@ -1,7 +0,0 @@ -@import (less) './assets/imported.css'; - -#link { - background-image: url('assets/person.png'); - background-size: contain; - background-repeat: no-repeat; -} \ No newline at end of file diff --git a/test/index.js b/test/index.js index 6f5fcb8..5ed8472 100644 --- a/test/index.js +++ b/test/index.js @@ -1,13 +1,163 @@ var inline = require('../lib'); -var path = require('path'); +var expect = require('chai') + .use(require('chai-as-promised')) + .expect; +var datauri = require('datauri'); var fs = require('fs'); +var path = require('path'); -var filepath = path.resolve(__dirname, './fixtures/index.html'); -var options = {verbose: true}; +describe('inlineHtml', function () { -inline(filepath, options) - .then(function (html) { - console.log(html); - fs.writeFileSync('./test.html', html); - }) - .catch(console.error); + it('html: filename', function () { + var filename = path.resolve(__dirname, './fixtures/file.txt'); + var content = fs.readFileSync(filename, 'utf8'); + return expect(inline(filename)).to.eventually.equal(content); + }); + it('html: string', function () { + var html = 'HTML'; + return expect(inline(html)).to.eventually.equal(html); + }); + + + it('inline link less', function () { + var filename = path.resolve(__dirname, 'fixtures/basic.less'); + var html = ``; + return expect(inline(html)).to.eventually.match(/`; + return expect(inline(html)).to.eventually.match(/data:.*,.*/); + }); + it('inline css url path in element style attribute', function () { + var filename = path.resolve(__dirname, 'fixtures/file.txt'); + var html = `
`; + return expect(inline(html)).to.eventually.match(/data:.*,.*/); + }); + it('inline img src', function () { + var filename = path.resolve(__dirname, 'fixtures/file.txt'); + var html = ``; + return expect(inline(html)).to.eventually.match(/data:.*,.*/); + }); + + + it('options.verbose: return results object if true', function () { + var filename = path.resolve(__dirname, 'fixtures/file.txt'); + var html = ``; + var options = { verbose: true }; + return expect(inline(html, options)).to.eventually.be.an('object') + .that.contains.keys(['html', 'files']); + }); + it('options.verbose: return html if false', function () { + var filename = path.resolve(__dirname, 'fixtures/file.txt'); + var html = ``; + var options = { verbose: false }; + return expect(inline(html, options)).to.eventually.be.a('string'); + }); + it('options.verbose: default false', function () { + var filename = path.resolve(__dirname, 'fixtures/file.txt'); + var html = ``; + return expect(inline(html)).to.eventually.be.a('string'); + }); + + + it('options.filename: ignored for css url path resolution if html filename', function () { + var html = path.resolve(__dirname, 'fixtures/css-url.html'); // file contains url path relative to itself + var options = { filename: __filename }; // sets filename relative to this test file + return expect(inline(html, options)).to.eventually.match(/"data:.*,.*"/); + }); + it('options.filename: ignored for img src path resolution if html filename', function () { + var html = path.resolve(__dirname, 'fixtures/img.html'); // file contains src relative to itself + var options = { filename: __filename }; // sets filename relative to this test file + return expect(inline(html, options)).to.eventually.match(/"data:.*,.*"/); + }); + it('options.filename: set basepath for css url path resolution if html string', function () { + var filename = path.resolve(__dirname, 'fixtures/fake.html'); + var dirname = path.dirname(filename); + + var url = 'file.txt'; // Note: path relative to filename's dirname + var uri = datauri(path.resolve(dirname, url)); + + var html = (path) => ``; + var options = { filename: filename }; + return expect(inline(html(url), options)).to.eventually.equal(html(uri)); + }); + it('options.filename: set basepath for img src path resolution if html string', function () { + var filename = path.resolve(__dirname, 'fixtures/fake.html'); + var dirname = path.dirname(filename); + + var url = 'file.txt'; // Note: path relative to filename's dirname + var uri = datauri(path.resolve(dirname, url)); + + var html = (path) => ``; + var options = { filename: filename }; + return expect(inline(html(url), options)).to.eventually.equal(html(uri)); + }); + it('options.filename: default to cwd for css url path resolution if html string', function () { + var url = 'test/fixtures/file.txt'; // Note: this is relative to cwd + var uri = datauri(url); + + var html = (path) => ``; + return expect(inline(html(url))).to.eventually.equal(html(uri)); + }); + it('options.filename: default to cwd for img src path resolution if html string', function () { + var url = 'test/fixtures/file.txt'; // Note: path relative to cwd + var uri = datauri(url); + + var html = (path) => ``; + return expect(inline(html(url))).to.eventually.equal(html(uri)); + }); + it('options.filename: included in results.files for img src if html string and options.verbose true', function () { + var filename = path.resolve(__dirname, 'fixtures/file.txt'); + var html = ``; + var options = { verbose: true }; + return expect(inline(html, options)).to.eventually.have.property('files') + .that.is.an('array') + .that.contains(filename); + }); + it('options.filename: included in results.files for css url path if html string and options.verbose true', function () { + var filename = path.resolve(__dirname, 'fixtures/file.txt'); + var html = ``; + var options = { verbose: true }; + return expect(inline(html, options)).to.eventually.have.property('files') + .that.is.an('array') + .that.contains(filename); + }); + + + it('preserve self closing tags', function () { + var html = '
'; + return expect(inline(html)).to.eventually.equal(html); + }); + it('preserve partials', function () { + var html = '{{> partial}}'; + return expect(inline(html)).to.eventually.equal(html); + }); + it('preserve helpers', function () { + var html = '{{helper}}'; + return expect(inline(html)).to.eventually.equal(html); + }); + + it('ignore css url remote paths', function () { + var html = ``; + return expect(inline(html)).to.eventually.equal(html); + }); + it('ignore img src remote paths', function () { + var html = ``; + return expect(inline(html)).to.eventually.equal(html); + }); + it('ignore query strings and hashes on local paths', function () { + var filename = path.resolve(__dirname, 'fixtures/file.txt'); + var url = `${filename}?query=string#hash`; + var uri = datauri(filename); + var html = (source) => ``; + return expect(inline(html(url))).to.eventually.equal(html(uri)); + }); + +}); diff --git a/test/inline-css-url.js b/test/inline-css-url.js deleted file mode 100644 index 0fbed5e..0000000 --- a/test/inline-css-url.js +++ /dev/null @@ -1,7 +0,0 @@ -var inline = require('../lib/inline-css-url'); -var fs = require('fs'); - -var filePath = './fixtures/assets/imported.css'; -var css = fs.readFileSync(filePath, 'utf8'); -var result = inline(css, filePath); -console.log(result.css); diff --git a/test/inline-link-less.js b/test/inline-link-less.js deleted file mode 100644 index 280568d..0000000 --- a/test/inline-link-less.js +++ /dev/null @@ -1,10 +0,0 @@ -var inline = require('../lib/inline-link-less'); -var fs = require('fs'); -var path = require('path'); - -var filepath = path.resolve(__dirname, './fixtures/index.html'); -var html = fs.readFileSync(filepath, 'utf8'); - -inline(html, filepath, {}) - .then(console.log) - .catch(console.error);