/* globals __dirname, URL */ import { JSDOM } from 'jsdom' import path from 'path' export default class FakeDom { constructor(content, options) { if (options === undefined) { options = {}; } // Header settings this.url = options.url || `file://${path.resolve(__dirname, '../../../../')}`; this.referer = options.referer; this.contentType = options.contentType || 'text/html'; // Content settings this.headStart = options.headStart || 'Fake document'; this.headEnd = options.headEnd || ''; this.bodyStart = options.bodyStart || ''; this.content = content || ''; this.bodyEnd = options.bodyEnd || ''; this.foot = options.foot || ''; // Callback settings this.beforeParse = (typeof options.beforeParse === 'function') ? options.beforeParse : undefined; // Assets this.css = []; this.scripts = []; this.inline = []; } static new(content, options) { return new FakeDom(content, options); } setContent(content) { this.content = content; return this; } addScript(script, id) { if (Array.isArray(script)) { script.forEach((item) => { this.addScript(item); }); return this; } let url = new URL(script, this.url); let base = new URL(this.url); if (url.host === base.host) { this.scripts.push({ url: `${url.pathname}`, id: id || this.generateId(), }); } else { this.scripts.push({ url, id: id || this.generateId(), }); } return this; } addCss(css, id) { if (Array.isArray(css)) { css.forEach((item) => { this.addCss(item) }); return this; } let url = new URL(css, this.url); let base = new URL(this.url); if (url.host === base.host) { this.css.push({ url: `${url.pathname}`, id: id || this.generateId(), }); } else { this.css.push({ url, id: id || this.generateId(), }); } return this; } addInlineScript(script, id) { this.inline.push({ script, id: id || this.generateId(), element: null, }); return this; } generateId() { let id = 'script-'; let chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-'; let charLength = chars.length; for (let i = 0; i < 10; i++) { let currentChar = chars.substr(Math.floor(Math.random() * charLength), 1); id = `${id}${currentChar}`; } return id; } render(content) { if (content) { this.content = content; } return new Promise((resolve, reject) => { try { const dom = new JSDOM( this._renderContent(), { url: this.url, referrer: this.referer, contentType: this.contentType, includeNodeLocations: true, runScripts: 'dangerously', resources: 'usable', pretendToBeVisual: true, beforeParse: this.beforeParse, } ); dom.window.resolver = () => { resolve(dom); }; } catch (e) { reject(e); } }); } _renderContent() { // Create content list const content = [this.headStart]; // Embed CSS this.css.forEach((css) => { content.push(``); }); content.push(this.headEnd, this.bodyStart, this.content); // Embed scripts this.scripts.forEach((script) => { content.push(``); }); this.inline.forEach((script) => { content.push(``); }); // Add resolver content.push(``); // Add final content content.push(this.bodyEnd); content.push(this.foot); return content.join('\n'); } }