123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- 'use strict'
- /**
- * # API
- * @author Ivan Voischev (@voischev),
- * Anton Winogradov (@awinogradov),
- * Alexej Yaroshevich (@zxqfox),
- * Vasiliy (@Yeti-or)
- * @module API
- * @namespace tree
- */
- module.exports = {
- /**
- * walk the tree and pass all nodes to callback
- *
- * @memberof tree
- * @param {Function} cb - Callback
- * @return {Function} - Node in callback
- *
- ***Usage**
- * ```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
- * })
- * }
- * ```
- */
- walk: function (cb) {
- return traverse(this, cb)
- },
- /**
- * match expression to search nodes in the tree
- *
- * @memberof tree
- * @param {String|RegExp|Object|Array} expression - Matcher(s) to search
- * @param {Function} cb - Callback
- * @return {Function} - Node in callback
- *
- ***Usage**
- * ```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
- * })
- * }
- * ```
- */
- match: function (expression, cb) {
- return Array.isArray(expression)
- ? traverse(this, function (node) {
- for (var i = 0; i < expression.length; i++) {
- if (compare(expression[i], node)) return cb(node)
- }
- return node
- })
- : traverse(this, function (node) {
- if (compare(expression, node)) return cb(node)
- return node
- })
- }
- }
- /** @private */
- function traverse (tree, cb) {
- if (Array.isArray(tree)) {
- for (var i = 0; i < tree.length; i++) {
- tree[i] = traverse(cb(tree[i]), cb)
- }
- } else if (
- tree &&
- typeof tree === 'object' &&
- tree.hasOwnProperty('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(function (exp) {
- return [].some.call(actual, function (act) {
- return compare(exp, act)
- })
- })
- }
- return Object.keys(expected).every(function (key) {
- var ao = actual[key]
- var 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
- })
- }
|