From 1027c9e88315952eee224b7a79afa40386d7e8dd Mon Sep 17 00:00:00 2001 From: Gerben Date: Thu, 12 Apr 2018 15:21:24 +0200 Subject: [PATCH] Initial implementation --- .gitignore | 2 ++ Readme.md | 28 ++++++++++++++++ package.json | 39 ++++++++++++++++++++++ src/index.js | 29 +++++++++++++++++ test/index.js | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 187 insertions(+) create mode 100644 Readme.md create mode 100644 package.json create mode 100644 src/index.js create mode 100644 test/index.js diff --git a/.gitignore b/.gitignore index e69de29..0ae7e5c 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +/lib diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..e885918 --- /dev/null +++ b/Readme.md @@ -0,0 +1,28 @@ +# document-outerhtml + +Like [Element.outerHTML][], but for the whole [Document][]. + +This means it returns a string containing the `.....` with all the content between, plus the `` declaration (if present), and any comments and stray elements or text nodes. + +# Install + + npm install document-outerhtml + +# Usage + + import documentOuterHTML from 'document-outerhtml' + + const html = documentOuterHTML(document) + +# Licence + +[CC0](https://creativecommons.org/publicdomain/zero/1.0/); do whatever you want with this code. + +# See also + + - [XMLSerializer.serializeToString][]; does nearly the same thing, except it creates XML. + + +[Element.outerHTML]: https://developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML +[Document]: https://developer.mozilla.org/en-US/docs/Web/API/Document +[XMLSerializer.serializeToString]: https://developer.mozilla.org/en-US/docs/Web/API/XMLSerializer/serializeToString diff --git a/package.json b/package.json new file mode 100644 index 0000000..9883c22 --- /dev/null +++ b/package.json @@ -0,0 +1,39 @@ +{ + "name": "document-outerhtml", + "version": "0.0.0", + "description": "Like Element.outerHTML, but for the whole Document.", + "keywords": [ + "dom" + ], + "main": "lib", + "scripts": { + "build": "babel -d lib src", + "prepublish": "npm run build", + "test": "ava" + }, + "author": "Gerben ", + "license": "CC0-1.0", + "files": [ + "lib" + ], + "devDependencies": { + "ava": "^1.0.0-beta.3", + "babel-cli": "^6.26.0", + "babel-preset-env": "^1.6.1", + "babel-register": "^6.26.0", + "window": "^4.2.5" + }, + "babel": { + "presets": [ + "env" + ] + }, + "ava": { + "require": [ + "babel-register" + ] + }, + "dependencies": { + "doctype-to-string": "^0.1.1" + } +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..531c25d --- /dev/null +++ b/src/index.js @@ -0,0 +1,29 @@ +import doctypeToString from 'doctype-to-string' + +export default function documentOuterHTML(document) { + if (!document + || document.nodeType === undefined + || document.nodeType !== document.DOCUMENT_NODE + ) { + throw new TypeError('Expected a Document') + } + const html = [...document.childNodes] + .map(node => nodeToString(node)) + .join('\n') + return html +} + +function nodeToString(node) { + switch (node.nodeType) { + case node.ELEMENT_NODE: + return node.outerHTML + case node.TEXT_NODE: + return node.textContent + case node.COMMENT_NODE: + return `` + case node.DOCUMENT_TYPE_NODE: + return doctypeToString(node) + default: + throw new TypeError(`Unexpected node type: ${node.nodeType}`) + } +} diff --git a/test/index.js b/test/index.js new file mode 100644 index 0000000..aad4cf0 --- /dev/null +++ b/test/index.js @@ -0,0 +1,89 @@ +import test from 'ava' +import Window from 'window'; + +import documentOuterHTML from '../src' + +function makeDocument(html) { + const window = new Window() + const parser = new window.DOMParser() + const doc = parser.parseFromString( + html, + 'text/html' + ) + return doc +} + +function normalise(html) { + // Remove whitespace around string and between tags. + return html.trim().replace(/>\s+<') +} + +test('should work with only an html node', t => { + const html = ` + + +

blub.

+ + ` + const doc = makeDocument(html) + t.is( + normalise(documentOuterHTML(doc)), + normalise(html) + ) +}) + +test('should work with comments', t => { + const html = ` + + + +

blub.

+ + + ` + const doc = makeDocument(html) + t.is( + normalise(documentOuterHTML(doc)), + normalise(html) + ) +}) + +test('should work with doctype', t => { + const html = ` + + + +

blub.

+ + ` + const doc = makeDocument(html) + t.is( + normalise(documentOuterHTML(doc)), + normalise(html) + ) +}) + +test('should work without a documentElement', t => { + const html = ` + + + ` + const doc = makeDocument(html) + // The html (+head&body) element will have been created automatically. Remove it. + doc.removeChild(doc.documentElement) + t.is( + normalise(documentOuterHTML(doc)), + normalise(html) + ) +}) + +test('should even work on a completely empty document', t => { + const html = `` + const doc = makeDocument(html) + // The html (+head&body) element will have been created automatically. Remove it. + doc.removeChild(doc.documentElement) + t.is( + normalise(documentOuterHTML(doc)), + normalise(html) + ) +})