is-callable
Advanced tools
Comparing version 1.1.5 to 1.2.0
@@ -0,1 +1,9 @@ | ||
1.2.0 / 2020-06-02 | ||
================= | ||
* [New] use `Reflect.apply`‑based callability detection | ||
* [readme] add install instructions (#55) | ||
* [meta] only run `aud` on prod deps | ||
* [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `tape`, `make-arrow-function`, `make-generator-function`; add `aud`, `safe-publish-latest`, `make-async-function` | ||
* [Tests] add tests for function proxies (#53, #25) | ||
1.1.5 / 2019-12-18 | ||
@@ -2,0 +10,0 @@ ================= |
47
index.js
'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 = {}; | ||
} catch (_) { | ||
reflectApply = null; | ||
} | ||
} else { | ||
reflectApply = null; | ||
} | ||
@@ -29,10 +46,22 @@ var constructorRegex = /^\s*class\b/; | ||
module.exports = function isCallable(value) { | ||
if (!value) { return false; } | ||
if (typeof value !== 'function' && typeof value !== 'object') { return false; } | ||
if (typeof value === 'function' && !value.prototype) { return true; } | ||
if (hasToStringTag) { return tryFunctionObject(value); } | ||
if (isES6ClassFn(value)) { return false; } | ||
var strClass = toStr.call(value); | ||
return strClass === fnClass || strClass === genClass; | ||
}; | ||
module.exports = reflectApply | ||
? function isCallable(value) { | ||
if (!value) { return false; } | ||
if (typeof value !== 'function' && typeof value !== 'object') { return false; } | ||
if (typeof value === 'function' && !value.prototype) { return true; } | ||
try { | ||
reflectApply(value, null, badArrayLike); | ||
} catch (e) { | ||
if (e !== isCallableMarker) { return false; } | ||
} | ||
return !isES6ClassFn(value); | ||
} | ||
: function isCallable(value) { | ||
if (!value) { return false; } | ||
if (typeof value !== 'function' && typeof value !== 'object') { return false; } | ||
if (typeof value === 'function' && !value.prototype) { return true; } | ||
if (hasToStringTag) { return tryFunctionObject(value); } | ||
if (isES6ClassFn(value)) { return false; } | ||
var strClass = toStr.call(value); | ||
return strClass === fnClass || strClass === genClass; | ||
}; |
{ | ||
"name": "is-callable", | ||
"version": "1.1.5", | ||
"version": "1.2.0", | ||
"author": { | ||
@@ -23,5 +23,6 @@ "name": "Jordan Harband", | ||
"scripts": { | ||
"prepublish": "safe-publish-latest", | ||
"pretest": "npm run --silent lint", | ||
"test": "npm run --silent tests-only", | ||
"posttest": "npx aud", | ||
"posttest": "npx aud --production", | ||
"tests-only": "npm run --silent test:stock && npm run --silent test:staging", | ||
@@ -59,13 +60,16 @@ "test:stock": "node test", | ||
"devDependencies": { | ||
"@ljharb/eslint-config": "^15.0.2", | ||
"@ljharb/eslint-config": "^17.1.0", | ||
"aud": "^1.1.2", | ||
"covert": "^1.1.1", | ||
"eclint": "^2.8.1", | ||
"eslint": "^6.7.2", | ||
"eslint": "^7.1.0", | ||
"foreach": "^2.0.5", | ||
"istanbul": "1.1.0-alpha.1", | ||
"istanbul-merge": "^1.1.1", | ||
"make-arrow-function": "^1.1.0", | ||
"make-generator-function": "^1.1.0", | ||
"make-arrow-function": "^1.2.0", | ||
"make-async-function": "^1.0.0", | ||
"make-generator-function": "^2.0.0", | ||
"rimraf": "^2.7.1", | ||
"tape": "^4.12.0" | ||
"safe-publish-latest": "^1.1.4", | ||
"tape": "^5.0.1" | ||
}, | ||
@@ -92,3 +96,8 @@ "testling": { | ||
"node": ">= 0.4" | ||
}, | ||
"greenkeeper": { | ||
"ignore": [ | ||
"rimraf" | ||
] | ||
} | ||
} |
@@ -42,3 +42,12 @@ # is-callable <sup>[![Version Badge][2]][1]</sup> | ||
## Install | ||
Install with | ||
``` | ||
npm install is-callable | ||
``` | ||
## Tests | ||
Simply clone the repo, `npm install`, and run `npm test` | ||
@@ -45,0 +54,0 @@ |
'use strict'; | ||
/* globals Proxy */ | ||
/* eslint no-magic-numbers: 1 */ | ||
@@ -8,12 +9,9 @@ | ||
var hasSymbols = typeof Symbol === 'function' && typeof Symbol('foo') === 'symbol'; | ||
var genFn = require('make-generator-function'); | ||
var arrowFn = require('make-arrow-function')(); | ||
var generators = require('make-generator-function')(); | ||
var arrows = require('make-arrow-function').list(); | ||
var asyncs = require('make-async-function').list(); | ||
var weirdlyCommentedArrowFn; | ||
var asyncFn; | ||
var asyncArrowFn; | ||
try { | ||
/* eslint-disable no-new-func */ | ||
weirdlyCommentedArrowFn = Function('return cl/*/**/=>/**/ass - 1;')(); | ||
asyncFn = Function('return async function foo() {};')(); | ||
asyncArrowFn = Function('return async () => {};')(); | ||
/* eslint-enable no-new-func */ | ||
@@ -34,2 +32,18 @@ } catch (e) { /**/ } | ||
var proxy; | ||
if (typeof Proxy === 'function') { | ||
try { | ||
proxy = new Proxy(function () {}, {}); | ||
// for coverage | ||
proxy(); | ||
String(proxy); | ||
} catch (_) { | ||
// If `Reflect` is supported, then `Function.prototype.toString` isn't used for callability detection. | ||
if (typeof Reflect !== 'object') { | ||
// Older engines throw a `TypeError` when `Function.prototype.toString` is called on a Proxy object. | ||
proxy = null; | ||
} | ||
} | ||
} | ||
var invokeFunction = function invokeFunctionString(str) { | ||
@@ -137,9 +151,13 @@ var result; | ||
test('Generators', { skip: !genFn }, function (t) { | ||
t.ok(isCallable(genFn), 'generator function is callable'); | ||
test('Generators', { skip: generators.length === 0 }, function (t) { | ||
forEach(generators, function (genFn) { | ||
t.ok(isCallable(genFn), 'generator function ' + genFn + ' is callable'); | ||
}); | ||
t.end(); | ||
}); | ||
test('Arrow functions', { skip: !arrowFn }, function (t) { | ||
t.ok(isCallable(arrowFn), 'arrow function is callable'); | ||
test('Arrow functions', { skip: arrows.length === 0 }, function (t) { | ||
forEach(arrows, function (arrowFn) { | ||
t.ok(isCallable(arrowFn), 'arrow function ' + arrowFn + ' is callable'); | ||
}); | ||
t.ok(isCallable(weirdlyCommentedArrowFn), 'weirdly commented arrow functions are callable'); | ||
@@ -158,6 +176,12 @@ t.end(); | ||
test('`async function`s', { skip: !asyncFn }, function (t) { | ||
t.ok(isCallable(asyncFn), '`async function`s are callable'); | ||
t.ok(isCallable(asyncArrowFn), '`async` arrow functions are callable'); | ||
test('`async function`s', { skip: asyncs.length === 0 }, function (t) { | ||
forEach(asyncs, function (asyncFn) { | ||
t.ok(isCallable(asyncFn), '`async function` ' + asyncFn + ' is callable'); | ||
}); | ||
t.end(); | ||
}); | ||
test('proxies of functions', { skip: !proxy }, function (t) { | ||
t.ok(isCallable(proxy), 'proxies of functions are callable'); | ||
t.end(); | ||
}); |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses eval() which is a dangerous function. This prevents the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
19915
14
223
69
2
14