kitchensink
Version:
Dispatch's awesome components and style guide
155 lines (119 loc) • 4.69 kB
JavaScript
function isArguments (obj) {
return Object.prototype.toString.call(obj) === '[object Arguments]'
}
module.exports = match
function match (obj, pattern) {
return match_(obj, pattern, [], [])
}
/* istanbul ignore next */
var log = (/\btmatch\b/.test(process.env.NODE_DEBUG || '')) ?
console.error : function () {}
function match_ (obj, pattern, ca, cb) {
log('TMATCH', typeof obj, pattern)
if (obj == pattern) {
log('TMATCH same object or simple value, or problem')
// if one is object, and the other isn't, then this is bogus
if (obj === null || pattern === null) {
return true
} else if (typeof obj === 'object' && typeof pattern === 'object') {
return true
} else if (typeof obj === 'object' && typeof pattern !== 'object') {
return false
} else if (typeof obj !== 'object' && typeof pattern === 'object') {
return false
} else {
return true
}
} else if (obj === null || pattern === null) {
log('TMATCH null test, already failed ==')
return false
} 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 if (obj instanceof Date && pattern instanceof Date) {
log('TMATCH date test')
return obj.getTime() === pattern.getTime()
} else if (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 if (pattern === Buffer) {
log('TMATCH Buffer ctor')
return Buffer.isBuffer(obj)
} else if (pattern === Function) {
log('TMATCH Function ctor')
return typeof obj === 'function'
} else if (pattern === Number) {
log('TMATCH Number ctor (finite, not NaN)')
return typeof obj === 'number' && obj === obj && isFinite(obj)
} else if (pattern !== pattern) {
log('TMATCH NaN')
return obj !== obj
} else if (pattern === String) {
log('TMATCH String ctor')
return typeof obj === 'string'
} else if (pattern === Boolean) {
log('TMATCH Boolean ctor')
return typeof obj === 'boolean'
} else if (pattern === Array) {
log('TMATCH Array ctor', pattern, Array.isArray(obj))
return Array.isArray(obj)
} else if (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 if (Buffer.isBuffer(obj) && Buffer.isBuffer(pattern)) {
log('TMATCH buffer test')
if (obj.equals) {
return obj.equals(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
}
/* istanbul ignore next */
throw new Error('impossible to reach this point')
}