| 'use strict' |
| |
| module.exports = match |
| |
| function isArguments (obj) { |
| return Object.prototype.toString.call(obj) === '[object Arguments]' |
| } |
| |
| function regexpSame (a, b) { |
| return a.source === b.source && |
| a.global === b.global && |
| a.multiline === b.multiline && |
| a.lastIndex === b.lastIndex && |
| a.ignoreCase === b.ignoreCase |
| } |
| |
| function arrayFrom (obj) { |
| return Array.isArray(obj) ? obj |
| : Array.from ? Array.from(obj) |
| : Array.prototype.slice.call(obj) |
| } |
| |
| var hasSet = typeof Set === 'function' |
| |
| function isSet (object) { |
| return hasSet && (object instanceof Set) |
| } |
| |
| function isMap (object) { |
| return hasSet && (object instanceof Map) |
| } |
| |
| function bufferSame (a, b) { |
| var ret |
| if (a.equals) { |
| ret = a.equals(b) |
| } else if (a.length !== b.length) { |
| ret = false |
| } else { |
| ret = true |
| for (var j = 0; j < a.length && ret; j++) { |
| if (a[j] != b[j]) |
| ret = false |
| } |
| } |
| return ret |
| } |
| |
| function match (obj, pattern) { |
| return match_(obj, pattern, [], []) |
| } |
| |
| function setMatch (obj, pattern) { |
| var ret = true |
| if (!isSet(obj)) |
| ret = false |
| else if (pattern.size === 0) |
| ret = true |
| else { |
| pattern.forEach(function (entry) { |
| if (ret) |
| ret = obj.has(entry) |
| }) |
| } |
| return ret |
| } |
| |
| function mapMatch (obj, pattern, ca, cb) { |
| var ret = true |
| if (!isMap(obj)) |
| ret = false |
| else if (pattern.size === 0) |
| ret = true |
| else { |
| pattern.forEach(function (value, key) { |
| if (ret) |
| ret = obj.has(key) |
| if (ret) |
| ret = match_(value, obj.get(key), ca, cb) |
| }) |
| } |
| return ret |
| } |
| |
| |
| function match_ (obj, pattern, ca, cb) { |
| return obj == pattern ? ( |
| obj === null || pattern === null ? true |
| : typeof obj === 'object' && typeof pattern === 'object' ? true |
| : typeof obj === 'object' && typeof pattern !== 'object' ? false |
| : typeof obj !== 'object' && typeof pattern === 'object' ? false |
| : true |
| ) |
| : obj === null || pattern === null ? false |
| : pattern instanceof RegExp ? ( |
| typeof obj === 'string' ? pattern.test(obj) |
| : obj instanceof RegExp ? regexpSame(obj, pattern) |
| : pattern.test('' + obj) |
| ) |
| : isSet(pattern) ? setMatch(obj, pattern) |
| : isMap(pattern) ? mapMatch(obj, pattern, ca, cb) |
| : typeof obj === 'string' && typeof pattern === 'string' && pattern ? |
| obj.indexOf(pattern) !== -1 |
| : obj instanceof Date && pattern instanceof Date ? |
| obj.getTime() === pattern.getTime() |
| : obj instanceof Date && typeof pattern === 'string' ? |
| obj.getTime() === new Date(pattern).getTime() |
| : isArguments(obj) || isArguments(pattern) ? |
| match_(arrayFrom(obj), arrayFrom(pattern), ca, cb) |
| : pattern === Buffer ? Buffer.isBuffer(obj) |
| : pattern === Function ? typeof obj === 'function' |
| : pattern === Number ? |
| typeof obj === 'number' && obj === obj && isFinite(obj) |
| : pattern !== pattern ? obj !== obj |
| : pattern === String ? typeof obj === 'string' |
| : pattern === Boolean ? typeof obj === 'boolean' |
| : pattern === Array ? Array.isArray(obj) |
| : typeof pattern === 'function' && typeof obj === 'object' ? |
| obj instanceof pattern |
| : typeof obj !== 'object' || typeof pattern !== 'object' ? false |
| : Buffer.isBuffer(obj) && Buffer.isBuffer(pattern) ? |
| bufferSame(obj, pattern) |
| : matchObj(obj, pattern, Object.keys(obj), Object.keys(pattern), ca, cb) |
| } |
| |
| function matchObj (obj, pattern, kobj, kpat, ca, cb) { |
| var ret = true |
| |
| // don't bother with stack acrobatics if there's nothing there |
| if (kobj.length === 0 && kpat.length === 0) |
| ret = true |
| else { |
| // 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 |
| var cal = ca.length |
| var go = true |
| while (cal-- && go) { |
| if (ca[cal] === obj && cb[cal] === pattern) { |
| ret = true |
| go = false |
| } |
| } |
| |
| if (go) { |
| ca.push(obj) |
| cb.push(pattern) |
| |
| var key |
| for (var l = kpat.length - 1; l >= 0 && ret; l--) { |
| key = kpat[l] |
| if (!match_(obj[key], pattern[key], ca, cb)) |
| ret = false |
| } |
| |
| if (ret) { |
| ca.pop() |
| cb.pop() |
| } |
| } |
| } |
| |
| return ret |
| } |