diff options
Diffstat (limited to 'node_modules/posthtml/lib/api.js')
| -rw-r--r-- | node_modules/posthtml/lib/api.js | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/node_modules/posthtml/lib/api.js b/node_modules/posthtml/lib/api.js new file mode 100644 index 0000000..e929cfb --- /dev/null +++ b/node_modules/posthtml/lib/api.js @@ -0,0 +1,145 @@ +'use strict' + +/** + * # API + * + * @author Ivan Voischev (@voischev), + * Anton Winogradov (@awinogradov), + * Alexej Yaroshevich (@zxqfox), + * Vasiliy (@Yeti-or) + * + * @namespace tree + */ +function Api () { + this.walk = walk + this.match = match +} + +/** + * Walks the tree and passes all nodes via a callback + * + * @memberof tree + * + * @param {Function} cb Callback + * @return {Function} Callback(node) + * + *@example + * ```js + * export const walk = (tree) => { + * tree.walk((node) => { + * let classes = node.attrs && node.attrs.class.split(' ') || [] + * + * if (classes.includes(className)) return cb(node) + * return node + * }) + * } + * ``` + */ +function walk (cb) { + return traverse(this, cb) +} + +/** + * Matches an expression to search for nodes in the tree + * + * @memberof tree + * + * @param {String|RegExp|Object|Array} expression - Matcher(s) to search + * @param {Function} cb Callback + * + * @return {Function} Callback(node) + * + * @example + * ```js + * export const match = (tree) => { + * // Single matcher + * tree.match({ tag: 'custom-tag' }, (node) => { + * let tag = node.tag + * + * Object.assign(node, { tag: 'div', attrs: {class: tag} }) + * + * return node + * }) + * // Multiple matchers + * tree.match([{ tag: 'b' }, { tag: 'strong' }], (node) => { + * let style = 'font-weight: bold;' + * + * node.tag = 'span' + * + * node.attrs + * ? ( node.attrs.style + * ? ( node.attrs.style += style ) + * : node.attrs.style = style + * ) + * : node.attrs = { style: style } + * + * return node + * }) + * } + * ``` + */ +function match (expression, cb) { + return Array.isArray(expression) + ? traverse(this, node => { + for (let i = 0; i < expression.length; i++) { + if (compare(expression[i], node)) return cb(node) + } + + return node + }) + : traverse(this, node => { + if (compare(expression, node)) return cb(node) + + return node + }) +} + +module.exports = Api +module.exports.match = match +module.exports.walk = walk + +/** @private */ +function traverse (tree, cb) { + if (Array.isArray(tree)) { + for (let i = 0; i < tree.length; i++) { + tree[i] = traverse(cb(tree[i]), cb) + } + } else if ( + tree && + typeof tree === 'object' && + Object.prototype.hasOwnProperty.call(tree, 'content') + ) traverse(tree.content, cb) + + return tree +} + +/** @private */ +function compare (expected, actual) { + if (expected instanceof RegExp) { + if (typeof actual === 'object') return false + if (typeof actual === 'string') return expected.test(actual) + } + + if (typeof expected !== typeof actual) return false + if (typeof expected !== 'object' || expected === null) { + return expected === actual + } + + if (Array.isArray(expected)) { + return expected.every(exp => [].some.call(actual, act => compare(exp, act))) + } + + return Object.keys(expected).every(key => { + const ao = actual[key] + const eo = expected[key] + + if (typeof eo === 'object' && eo !== null && ao !== null) { + return compare(eo, ao) + } + if (typeof eo === 'boolean') { + return eo !== (ao == null) + } + + return ao === eo + }) +} |
