'use strict'; 
 | 
  
 | 
exports.isInteger = num => { 
 | 
  if (typeof num === 'number') { 
 | 
    return Number.isInteger(num); 
 | 
  } 
 | 
  if (typeof num === 'string' && num.trim() !== '') { 
 | 
    return Number.isInteger(Number(num)); 
 | 
  } 
 | 
  return false; 
 | 
}; 
 | 
  
 | 
/** 
 | 
 * Find a node of the given type 
 | 
 */ 
 | 
  
 | 
exports.find = (node, type) => node.nodes.find(node => node.type === type); 
 | 
  
 | 
/** 
 | 
 * Find a node of the given type 
 | 
 */ 
 | 
  
 | 
exports.exceedsLimit = (min, max, step = 1, limit) => { 
 | 
  if (limit === false) return false; 
 | 
  if (!exports.isInteger(min) || !exports.isInteger(max)) return false; 
 | 
  return ((Number(max) - Number(min)) / Number(step)) >= limit; 
 | 
}; 
 | 
  
 | 
/** 
 | 
 * Escape the given node with '\\' before node.value 
 | 
 */ 
 | 
  
 | 
exports.escapeNode = (block, n = 0, type) => { 
 | 
  let node = block.nodes[n]; 
 | 
  if (!node) return; 
 | 
  
 | 
  if ((type && node.type === type) || node.type === 'open' || node.type === 'close') { 
 | 
    if (node.escaped !== true) { 
 | 
      node.value = '\\' + node.value; 
 | 
      node.escaped = true; 
 | 
    } 
 | 
  } 
 | 
}; 
 | 
  
 | 
/** 
 | 
 * Returns true if the given brace node should be enclosed in literal braces 
 | 
 */ 
 | 
  
 | 
exports.encloseBrace = node => { 
 | 
  if (node.type !== 'brace') return false; 
 | 
  if ((node.commas >> 0 + node.ranges >> 0) === 0) { 
 | 
    node.invalid = true; 
 | 
    return true; 
 | 
  } 
 | 
  return false; 
 | 
}; 
 | 
  
 | 
/** 
 | 
 * Returns true if a brace node is invalid. 
 | 
 */ 
 | 
  
 | 
exports.isInvalidBrace = block => { 
 | 
  if (block.type !== 'brace') return false; 
 | 
  if (block.invalid === true || block.dollar) return true; 
 | 
  if ((block.commas >> 0 + block.ranges >> 0) === 0) { 
 | 
    block.invalid = true; 
 | 
    return true; 
 | 
  } 
 | 
  if (block.open !== true || block.close !== true) { 
 | 
    block.invalid = true; 
 | 
    return true; 
 | 
  } 
 | 
  return false; 
 | 
}; 
 | 
  
 | 
/** 
 | 
 * Returns true if a node is an open or close node 
 | 
 */ 
 | 
  
 | 
exports.isOpenOrClose = node => { 
 | 
  if (node.type === 'open' || node.type === 'close') { 
 | 
    return true; 
 | 
  } 
 | 
  return node.open === true || node.close === true; 
 | 
}; 
 | 
  
 | 
/** 
 | 
 * Reduce an array of text nodes. 
 | 
 */ 
 | 
  
 | 
exports.reduce = nodes => nodes.reduce((acc, node) => { 
 | 
  if (node.type === 'text') acc.push(node.value); 
 | 
  if (node.type === 'range') node.type = 'text'; 
 | 
  return acc; 
 | 
}, []); 
 | 
  
 | 
/** 
 | 
 * Flatten an array 
 | 
 */ 
 | 
  
 | 
exports.flatten = (...args) => { 
 | 
  const result = []; 
 | 
  const flat = arr => { 
 | 
    for (let i = 0; i < arr.length; i++) { 
 | 
      let ele = arr[i]; 
 | 
      Array.isArray(ele) ? flat(ele, result) : ele !== void 0 && result.push(ele); 
 | 
    } 
 | 
    return result; 
 | 
  }; 
 | 
  flat(args); 
 | 
  return result; 
 | 
}; 
 |