Files
2026-03-03 23:49:13 +01:00

439 lines
10 KiB
JavaScript

"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_END = '-->';
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' && /<!(?:--)?\[[\S\s]*?]>/.test(node)) {
const conditional = /^((?:<[^>]+>)?<!(?:--)?\[[\S\s]*?]>(?:<!)?(?:-->)?)([\S\s]*?)(<!(?:--<!)?\[[\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' && /<!(?:--)?\[endif]*?]>/.test(node)) {
return [...previousValue, getIndent(level, {
indent,
eol
}), node, blankLines];
}
if (typeof node === 'string' && /<!(?:--)?\[[\S\s]*?]>/.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;