You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							136 lines
						
					
					
						
							3.2 KiB
						
					
					
				
			
		
		
	
	
							136 lines
						
					
					
						
							3.2 KiB
						
					
					
				'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 | 
						|
  }) | 
						|
}
 | 
						|
 |