"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _posthtmlParser = _interopRequireDefault(require("posthtml-parser")); var _posthtmlRender = _interopRequireDefault(require("posthtml-render")); var _api = require("posthtml/lib/api"); var _rules = _interopRequireDefault(require("./rules.js")); var _attrs = _interopRequireDefault(require("./attrs.js")); var _tags = _interopRequireDefault(require("./tags.js")); var _deepmerge = _interopRequireDefault(require("deepmerge")); var _jsBeautify = require("js-beautify"); const optionsDefault = { rules: _rules.default, attrs: _attrs.default, tags: _tags.default, sync: false, commentFormat: true, mini: { removeAttribute: false }, jsBeautifyOptions: { indent_size: 2, // eslint-disable-line camelcase jslint_happy: true // eslint-disable-line camelcase } }; const COMMENT_START = ''; const COMMENT_CONTENT_REG = new RegExp(`${COMMENT_START}([\\S\\s]*?)${COMMENT_END}`); const nodeHasContent = (node, callback) => { if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'content')) { node.content = callback(node.content); } }; const nodeHasAttrs = (node, callback) => { if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'attrs')) { node.attrs = Object.keys(node.attrs).reduce(callback, {}); } }; const getIndent = (level, { indent, eol }) => { const indentString = typeof indent === 'number' ? ' '.repeat(indent) : '\t'; return `${eol}${indentString.repeat(level)}`; }; const clean = tree => (0, _posthtmlParser.default)((0, _posthtmlRender.default)(tree)).filter(node => { return typeof node === 'object' || typeof node === 'string' && (node.trim().length !== 0 || /doctype/gi.test(node)); }).map(node => { if (Object.prototype.hasOwnProperty.call(node, 'content')) { node.content = clean(node.content); } return typeof node === 'string' ? node.trim() : node; }); const parseConditional = tree => { return tree.map(node => { nodeHasContent(node, parseConditional); if (typeof node === 'string' && //.test(node)) { const conditional = /^((?:<[^>]+>)?(?:)?)([\S\s]*?)()$/.exec(node).slice(1).map((node, index) => index === 1 ? { tag: 'conditional-content', content: clean((0, _posthtmlParser.default)(node)) } : node); return { tag: 'conditional', content: conditional }; } return node; }); }; const renderConditional = tree => { return tree.reduce((previousValue, node) => { if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'content')) { node.content = renderConditional(node.content); } if (typeof node === 'object' && node.tag === 'conditional') { return [...previousValue, ...node.content]; } if (typeof node === 'object' && node.tag === 'conditional-content') { node.tag = false; return [...previousValue, node]; } return [...previousValue, node]; }, []); }; const indent = (tree, { rules: { indent, eol, blankLines, maxlen } }) => { const setIndent = (tree, level = 0) => tree.reduce((previousValue, node, index) => { if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'content')) { node.content = setIndent(node.content, ++level); --level; } if (tree.length === 1 && typeof tree[index] === 'string') { if (tree[index].length >= maxlen) { return [...previousValue, getIndent(level, { indent, eol }), node, getIndent(--level, { indent, eol })]; } return [...previousValue, node]; } if (level === 0 && tree.length - 1 === index && tree.length > 1) { return [...previousValue, getIndent(level, { indent, eol }), node]; } if (level === 0 && tree.length - 1 === index && tree.length === 1) { return [...previousValue, node]; } if (level === 0 && index === 0) { return [...previousValue, node, blankLines]; } if (level === 0) { return [...previousValue, getIndent(level, { indent, eol }), node, blankLines]; } if (tree.length - 1 === index) { return [...previousValue, getIndent(level, { indent, eol }), node, getIndent(--level, { indent, eol })]; } if (typeof node === 'string' && //.test(node)) { return [...previousValue, getIndent(level, { indent, eol }), node, blankLines]; } if (typeof node === 'string' && //.test(node)) { return [...previousValue, getIndent(level, { indent, eol }), node]; } if (node.tag === false) { return [...previousValue, ...node.content.slice(0, -1)]; } return [...previousValue, getIndent(level, { indent, eol }), node, blankLines]; }, []); return setIndent(tree); }; const attributesBoolean = (tree, { attrs: { boolean } }) => { const removeAttributeValue = tree => tree.map(node => { nodeHasContent(node, removeAttributeValue); if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'attrs')) { Object.keys(node.attrs).forEach(key => { node.attrs[key] = boolean.includes(key) || node.attrs[key].trim().split(' ').filter(value => value.length).join(' '); }); } return node; }); return removeAttributeValue(tree); }; const lowerElementName = (tree, { tags }) => { tags = tags.map(({ name }) => name); const bypass = tree => tree.map(node => { nodeHasContent(node, bypass); if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'tag') && tags.includes(node.tag.toLowerCase())) { node.tag = node.tag.toLowerCase(); } return node; }); return bypass(tree); }; const lowerAttributeName = tree => { const bypass = tree => tree.map(node => { nodeHasContent(node, bypass); nodeHasAttrs(node, (previousValue, key) => Object.assign(previousValue, { [key.toLowerCase()]: node.attrs[key] })); return node; }); return bypass(tree); }; const eof = (tree, { rules: { eof } }) => eof ? [...tree, eof] : tree; const mini = (tree, { mini }) => { const bypass = tree => tree.map(node => { nodeHasContent(node, bypass); nodeHasAttrs(node, (previousValue, key) => { if (mini.removeAttribute && mini.removeAttribute === 'empty' && node.attrs[key].length === 0) { return previousValue; } return Object.assign(previousValue, { [key.toLowerCase()]: node.attrs[key] }); }); return node; }); return bypass(tree); }; const sortLogic = function (key1, key2) { if (key1 < key2) { return -1; } if (key1 > key2) { return 1; } return 0; }; const sortAttr = (tree, { rules: { sortAttr } }) => { tree.walk = _api.walk; tree.walk(node => { if (sortAttr && node.attrs) { const keys = Object.keys(node.attrs); if (keys.length > 1) { node.attrs = keys.sort(sortLogic).reduce((current, key) => Object.assign(current, { [key]: node.attrs[key] }), {}); } } return node; }); delete tree.walk; return tree; }; const jsPrettier = (tree, { rules: { indent, eol }, jsBeautifyOptions }) => { let level = 0; const prettier = tree => tree.map(node => { ++level; nodeHasContent(node, prettier); if (node.tag === 'script') { const content = node.content ? ['\n', (0, _jsBeautify.js)(node.content.join(''), { ...jsBeautifyOptions, indent_level: level // eslint-disable-line camelcase }), getIndent(--level, { indent, eol })] : ['']; node.content = content; } --level; return node; }); return prettier(tree); }; const addLang = (tree, { rules: { lang } }) => { if (!lang) { return tree; } tree.walk = _api.walk; tree.walk(node => { if (node.tag) { if (!node.attrs) { node.attrs = { lang }; return node; } nodeHasAttrs(node, (previousValue, key) => { return Object.assign({}, { lang, [key]: node.attrs[key] }, previousValue); }); } return node; }); delete tree.walk; return tree; }; const commentsFormatting = (tree, { commentFormat }) => { if (!commentFormat) { return tree; } tree.walk = _api.walk; tree.walk(node => { if (typeof node === 'string') { const contentMatch = node.match(COMMENT_CONTENT_REG); if (contentMatch === null) { return node; } const content = contentMatch[1].trim().split('\n').map(part => part.trim()).filter(Boolean); return [COMMENT_START, ...content, COMMENT_END].join(content.length === 1 ? ' ' : '\n'); } return node; }); delete tree.walk; return tree; }; const beautify = (tree, options) => [clean, parseConditional, renderConditional, commentsFormatting, indent, jsPrettier, lowerElementName, lowerAttributeName, attributesBoolean, sortAttr, addLang, eof, mini].reduce((previousValue, module) => typeof module === 'function' ? module(previousValue, options) : previousValue, tree); const normalize = (node, options) => { let { tree, api } = Object.keys(node).reduce((scope, key) => { scope[Number.isNaN(Number(key)) ? 'api' : 'tree'][key] = node[key]; return scope; }, { tree: [], api: [] }); tree = beautify(tree, (0, _deepmerge.default)(optionsDefault, options)); for (const [key, value] of Object.entries(api)) { tree[key] = value; } return tree; }; var _default = (options = {}) => node => { if (!Array.isArray(node)) { throw new TypeError('tree is not Array'); } if (node.length === 0) { return node; } return normalize(node, options); }; exports.default = _default; module.exports = exports.default;