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.
101 lines
3.1 KiB
101 lines
3.1 KiB
'use strict'; |
|
|
|
var fnToStr = Function.prototype.toString; |
|
var reflectApply = typeof Reflect === 'object' && Reflect !== null && Reflect.apply; |
|
var badArrayLike; |
|
var isCallableMarker; |
|
if (typeof reflectApply === 'function' && typeof Object.defineProperty === 'function') { |
|
try { |
|
badArrayLike = Object.defineProperty({}, 'length', { |
|
get: function () { |
|
throw isCallableMarker; |
|
} |
|
}); |
|
isCallableMarker = {}; |
|
// eslint-disable-next-line no-throw-literal |
|
reflectApply(function () { throw 42; }, null, badArrayLike); |
|
} catch (_) { |
|
if (_ !== isCallableMarker) { |
|
reflectApply = null; |
|
} |
|
} |
|
} else { |
|
reflectApply = null; |
|
} |
|
|
|
var constructorRegex = /^\s*class\b/; |
|
var isES6ClassFn = function isES6ClassFunction(value) { |
|
try { |
|
var fnStr = fnToStr.call(value); |
|
return constructorRegex.test(fnStr); |
|
} catch (e) { |
|
return false; // not a function |
|
} |
|
}; |
|
|
|
var tryFunctionObject = function tryFunctionToStr(value) { |
|
try { |
|
if (isES6ClassFn(value)) { return false; } |
|
fnToStr.call(value); |
|
return true; |
|
} catch (e) { |
|
return false; |
|
} |
|
}; |
|
var toStr = Object.prototype.toString; |
|
var objectClass = '[object Object]'; |
|
var fnClass = '[object Function]'; |
|
var genClass = '[object GeneratorFunction]'; |
|
var ddaClass = '[object HTMLAllCollection]'; // IE 11 |
|
var ddaClass2 = '[object HTML document.all class]'; |
|
var ddaClass3 = '[object HTMLCollection]'; // IE 9-10 |
|
var hasToStringTag = typeof Symbol === 'function' && !!Symbol.toStringTag; // better: use `has-tostringtag` |
|
|
|
var isIE68 = !(0 in [,]); // eslint-disable-line no-sparse-arrays, comma-spacing |
|
|
|
var isDDA = function isDocumentDotAll() { return false; }; |
|
if (typeof document === 'object') { |
|
// Firefox 3 canonicalizes DDA to undefined when it's not accessed directly |
|
var all = document.all; |
|
if (toStr.call(all) === toStr.call(document.all)) { |
|
isDDA = function isDocumentDotAll(value) { |
|
/* globals document: false */ |
|
// in IE 6-8, typeof document.all is "object" and it's truthy |
|
if ((isIE68 || !value) && (typeof value === 'undefined' || typeof value === 'object')) { |
|
try { |
|
var str = toStr.call(value); |
|
return ( |
|
str === ddaClass |
|
|| str === ddaClass2 |
|
|| str === ddaClass3 // opera 12.16 |
|
|| str === objectClass // IE 6-8 |
|
) && value('') == null; // eslint-disable-line eqeqeq |
|
} catch (e) { /**/ } |
|
} |
|
return false; |
|
}; |
|
} |
|
} |
|
|
|
module.exports = reflectApply |
|
? function isCallable(value) { |
|
if (isDDA(value)) { return true; } |
|
if (!value) { return false; } |
|
if (typeof value !== 'function' && typeof value !== 'object') { return false; } |
|
try { |
|
reflectApply(value, null, badArrayLike); |
|
} catch (e) { |
|
if (e !== isCallableMarker) { return false; } |
|
} |
|
return !isES6ClassFn(value) && tryFunctionObject(value); |
|
} |
|
: function isCallable(value) { |
|
if (isDDA(value)) { return true; } |
|
if (!value) { return false; } |
|
if (typeof value !== 'function' && typeof value !== 'object') { return false; } |
|
if (hasToStringTag) { return tryFunctionObject(value); } |
|
if (isES6ClassFn(value)) { return false; } |
|
var strClass = toStr.call(value); |
|
if (strClass !== fnClass && strClass !== genClass && !(/^\[object HTML/).test(strClass)) { return false; } |
|
return tryFunctionObject(value); |
|
};
|
|
|