Code coverage report for index.js

Statements: 69% (69 / 100)      Branches: 74.42% (64 / 86)      Functions: 100% (4 / 4)      Lines: 69.23% (63 / 91)      Ignored: none     

All files » __root__/ » index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173    1 108     1   1 49     1 1                                                             1     1 105   105 40 40   65 1 1   64 5 5   59 2 2   57       57 2 2   55       55 2 2 2   53       53       53       53       53       53       53       53 10 10   43 4 4           39                               39 39 39 39     39         37 37 37 36 36   36 36 54 54 54     30   30 30            
'use strict'
 
function isArguments (obj) {
  return Object.prototype.toString.call(obj) === '[object Arguments]'
}
 
module.exports = match
 
function match (obj, pattern) {
  return match_(obj, pattern, [], [])
}
 
try {
  match.fastEqual = require('buffertools').equals
} catch (e) {
  // whoops, nobody told buffertools it wasn't installed
}
 
/**
1. If the object is a string, and the pattern is a RegExp, then return
   true if `pattern.test(object)`.
2. Use loose equality (`==`) only for all other value types
   (non-objects).  `tmatch` cares more about shape and contents than
   type. This step will also catch functions, with the useful
   (default) property that only references to the same function are
   considered equal.  'Ware the halting problem!
3. `null` *is* an object – a singleton value object, in fact – so if
   either is `null`, return object == pattern.
4. Since the only way to make it this far is for `object` or `pattern`
   to be an object, if `object` or `pattern` is *not* an object,
   they're clearly not a match.
5. It's much faster to compare dates by numeric value (`.getTime()`)
   than by lexical value.
6. Compare RegExps by their components, not the objects themselves.
7. The parts of an arguments list most people care about are the
   arguments themselves, not the callee, which you shouldn't be
   looking at anyway.
8. Objects are more complex:
   1. Return `true` if `object` and `pattern` both have no properties.
   2. Ensure that cyclical references don't blow up the stack.
   3. Ensure that all the key names in `pattern` exist in `object`.
   4. Ensure that all of the associated values match, recursively.
*/
 
var log = (/\btmatch\b/.test(process.env.NODE_DEBUG || '')) ?
  console.error : function () {}
 
function match_ (obj, pattern, ca, cb) {
  log('TMATCH', typeof obj, pattern)
  /*eslint eqeqeq:0*/
  if (obj == pattern) {
    log('TMATCH same object or simple value, true')
    return true
 
  } else if (obj === null || pattern === null) {
    log('TMATCH null test')
    return obj == pattern
 
  } else if (typeof obj === 'string' && pattern instanceof RegExp) {
    log('TMATCH string~=regexp test')
    return pattern.test(obj)
 
  } else if (typeof obj === 'string' && typeof pattern === 'string' && pattern) {
    log('TMATCH string~=string test')
    return obj.indexOf(pattern) !== -1
 
  } else Iif (pattern === Buffer) {
    log('TMATCH Buffer ctor')
    return Buffer.isBuffer(obj)
 
  } else if (obj instanceof Date && pattern instanceof Date) {
    log('TMATCH date test')
    return obj.getTime() === pattern.getTime()
 
  } else Iif (obj instanceof Date && typeof pattern === 'string') {
    log('TMATCH date~=string test')
    return obj.getTime() === new Date(pattern).getTime()
 
  } else if (isArguments(obj) || isArguments(pattern)) {
    log('TMATCH arguments test')
    var slice = Array.prototype.slice
    return match_(slice.call(obj), slice.call(pattern), ca, cb)
 
  } else Iif (pattern === Function) {
    log('TMATCH Function ctor')
    return typeof obj === 'function'
 
  } else Iif (pattern === Number) {
    log('TMATCH Number ctor')
    return typeof obj === 'number' && obj === obj
 
  } else Iif (pattern !== pattern) {
    log('TMATCH NaN')
    return obj !== obj
 
  } else Iif (pattern === String) {
    log('TMATCH String ctor')
    return typeof obj === 'string'
 
  } else Iif (pattern === Boolean) {
    log('TMATCH Boolean ctor')
    return typeof obj === 'boolean'
 
  } else Iif (pattern === Array) {
    log('TMATCH Array ctor')
    return Array.isArray(pattern)
 
  } else Iif (typeof pattern === 'function' && typeof obj === 'object') {
    log('TMATCH object~=function')
    return obj instanceof pattern
 
  } else if (typeof obj !== 'object' || typeof pattern !== 'object') {
    log('TMATCH obj is not object, pattern is not object, false')
    return false
 
  } else if (obj instanceof RegExp && pattern instanceof RegExp) {
    log('TMATCH regexp~=regexp test')
    return obj.source === pattern.source &&
    obj.global === pattern.global &&
    obj.multiline === pattern.multiline &&
    obj.lastIndex === pattern.lastIndex &&
    obj.ignoreCase === pattern.ignoreCase
 
  } else Iif (Buffer.isBuffer(obj) && Buffer.isBuffer(pattern)) {
    log('TMATCH buffer test')
    if (obj.equals) {
      return obj.equals(pattern)
    } else if (match.fastEqual) {
      return match.fastEqual.call(obj, pattern)
    } else {
      if (obj.length !== pattern.length) return false
 
      for (var j = 0; j < obj.length; j++) if (obj[j] != pattern[j]) return false
 
      return true
    }
 
  } else {
    // both are objects.  interesting case!
    log('TMATCH object~=object test')
    var kobj = Object.keys(obj)
    var kpat = Object.keys(pattern)
    log('  TMATCH patternkeys=%j objkeys=%j', kpat, kobj)
 
    // don't bother with stack acrobatics if there's nothing there
    if (kobj.length === 0 && kpat.length === 0) return true
 
    // if we've seen this exact pattern and object already, then
    // it means that pattern and obj have matching cyclicalness
    // however, non-cyclical patterns can match cyclical objects
    log('  TMATCH check seen objects...')
    var cal = ca.length
    while (cal--) if (ca[cal] === obj && cb[cal] === pattern) return true
    ca.push(obj); cb.push(pattern)
    log('  TMATCH not seen previously')
 
    var key
    for (var l = kpat.length - 1; l >= 0; l--) {
      key = kpat[l]
      log('  TMATCH test obj[%j]', key, obj[key], pattern[key])
      if (!match_(obj[key], pattern[key], ca, cb)) return false
    }
 
    ca.pop(); cb.pop()
 
    log('  TMATCH object pass')
    return true
  }
 
  log('TMATCH no way to match')
  return false
}