UNPKG

infuse.host

Version:

Infuse your HTML with dynamic content.

113 lines (92 loc) 3.55 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.getDoctype = undefined; exports.default = parseDocument; var _crypto = require('crypto'); var _crypto2 = _interopRequireDefault(_crypto); var _domino = require('domino'); var _domino2 = _interopRequireDefault(_domino); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // Default doctype. const DEFAULT_DOCTYPE = '<!DOCTYPE html>'; /** * Gets the DOCTYPE string of a document. Returns `null` if the document has no DTD: * https://developer.mozilla.org/en-US/docs/Web/API/document/doctype * Inspired by https://stackoverflow.com/a/10162353/588283 * * @function getDoctype * @param {Document} document The document object. * @returns {string} The document's DOCTYPE string or `null` if it doesn't have one. */ const getDoctype = exports.getDoctype = function getDoctypeString(document) { const type = document.doctype; if (type === null) { return null; } let specs = type.name; if (type.publicId) { specs += ` PUBLIC "${type.publicId}"`; } if (!type.publicId && type.systemId) { specs += ' SYSTEM'; } if (type.systemId) { specs += ` "${type.systemId}"`; } return `<!DOCTYPE ${specs}>`; }; /** * Parses a HTML document. An MD5 hash is alse generated using the provided `htmlDocument`. * * @function parseDocument * @param {(string|Document)} htmlDocument The HTML source code to parse or a parsed `Document`. * @returns {Object} An object with the following attributes: * * `document`: The parsed document. * * `doctype`: The document's DOCTYPE string. * * `window`: The window used to parse the document. * * `hash`: The first few characters of the MD5 hash of the provided `htmlDocument` */ function parseDocument(htmlDocument) { let document, doctype, html, window; if (typeof htmlDocument === 'string') { // If the `htmlDocument` is a string, use domino to parse it into a document. html = htmlDocument.trim(); // If `html` has a DOCTYPE, remove it and assign it to `doctype`. if (html.substr(0, 10).toUpperCase() === '<!DOCTYPE ') { const i = html.indexOf('>', 10); doctype = html.substring(0, i + 1); html = html.substr(i + 1).trim(); } else { doctype = DEFAULT_DOCTYPE; } // If `html` doesn't have a <html> and a <body>, put it inside a <body> element. if (html.indexOf('<html') === -1 && html.indexOf('<body') === -1) { /** * If `html` doesn't have a <body> and doesn't start with a <template> assume that the * entire HTML code is meant to be inside a single <template> element. */ if (html.substr(0, 9).toLowerCase() !== '<template') { html = `<template>${html}</template>`; } html = `<body>${html}</body>`; } // Parse `html` into a `document`. document = _domino2.default.createDocument(`${doctype}\n${html}`); // Use the original `htmlDocument` to calculate the hash below. html = htmlDocument; // Use domino's implementation of the window interface as `window`. window = _domino2.default.impl; } else { // If `htmlDocument` is NOT a string, assume it's an instance of `Document`. document = htmlDocument; window = document.defaultView; doctype = getDoctype(document) || DEFAULT_DOCTYPE; html = `${doctype}\n${document.documentElement.outerHTML}`; } // Calculate a hash of `html`. const hash = _crypto2.default.createHash('md5').update(html).digest('hex'); // eslint-disable-next-line object-curly-newline return { doctype, document, hash, window }; }