UNPKG

@markedjs/html-differ

Version:
114 lines (97 loc) 3.48 kB
import { SAXParser } from 'parse5-sax-parser'; import * as serialize from './serialize.js'; import * as utils from './utils.js'; /** * Parses the given HTML and modifies it according to the given options * @param {String} value * @param {Object} [options] * @param {String[]} [options.ignoreAttributes] * @param {String[]} [options.compareAttributesAsJSON] * @param {Boolean} [options.ignoreWhitespaces=true] * @param {Boolean} [options.ignoreComments=true] * @param {Boolean} [options.ignoreEndTags=false] * @param {Boolean} [options.ignoreSelfClosingSlash=false] * returns {String} */ export default function modify(value, options) { return new Promise((resolve, reject) => { const modifiedValues = []; const parser = new SAXParser(); /** * @param {object} doctypeToken * @param {String} doctypeToken.name * @param {String} doctypeToken.publicId * @param {String} doctypeToken.systemId */ parser.on('doctype', function(doctypeToken) { const name = doctypeToken.name; const publicId = doctypeToken.publicId; const systemId = doctypeToken.systemId; modifiedValues.push(serialize.doctype(name, publicId, systemId)); }); /** * @param {object} startTagToken * @param {String} startTagToken.tagName * @param {Array} startTagToken.attrs * @param {Boolean} startTagToken.selfClosing */ parser.on('startTag', function(startTagToken) { let attrs = startTagToken.attrs; let selfClosing = startTagToken.selfClosing; const tagName = startTagToken.tagName; if (options.ignoreSelfClosingSlash) { selfClosing = false; } attrs = utils.sortAttrs(attrs) && utils.sortCssClasses(attrs) && utils.sortAttrsValues(attrs, options.compareAttributesAsJSON) && utils.removeAttrsValues(attrs, options.ignoreAttributes); modifiedValues.push(serialize.startTag(tagName, attrs, selfClosing)); }); /** * @param {object} endTagToken * @param {String} endTagToken.tagName */ parser.on('endTag', function(endTagToken) { const tagName = endTagToken.tagName; if (!options.ignoreEndTags) { modifiedValues.push(serialize.endTag(tagName)); } }); /** * @param {object} textToken * @param {String} textToken.text */ parser.on('text', function(textToken) { let text = textToken.text; if (options.ignoreWhitespaces) { text = utils.removeWhitespaces(text); } modifiedValues.push(serialize.text(text)); }); /** * @param {object} commentToken * @param {String} commentToken.text */ parser.on('comment', function(commentToken) { modifiedValues.push(new Promise(resolve => { const comment = commentToken.text; resolve(utils.getConditionalComment(comment, modify, options)); }).then(conditionalComment => { if (conditionalComment) { return serialize.comment(conditionalComment); } else if (!options.ignoreComments) { return serialize.comment(commentToken.text); } })); }); parser.on('end', async function() { const values = await Promise.all(modifiedValues); resolve(values.join('')); }); parser.on('error', function(err) { reject(err); }); parser.end(value); }); }