Skip to content

Commit e04a85c

Browse files
committed
Fixed README.md, webpack config, test pages. Add MIT license.
0 parents  commit e04a85c

12 files changed

+654
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
(The MIT License)
2+
3+
Copyright (c) 2016 uid-11222
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
'Software'), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# is-pure-function #
2+
3+
[![NPM version][npm-image]][npm-url] ![dependencies][dependencies-image] [![License MIT][license-image]](LICENSE)
4+
5+
Simple and fast ES3-check that function is pure.
6+
7+
```js
8+
/**
9+
* @param {function} fn
10+
* @param {*} thisArg
11+
* @param {Array} args
12+
* @return {boolean}
13+
*/
14+
function isPureFunction(fn, thisArg, args) {};
15+
```
16+
17+
*fn* is pure, if not throw when called with *thisArg* as this and *args* as arguments in global scope.
18+
19+
Pure function cannot use closures, but can use exists global vars (Array, Object, setTimeout, etc.).
20+
Pure function should not have side effects, and cannot throw exceptions.
21+
Arrow function may be pure, but then it should not contain 'this' and 'arguments' words.
22+
Generators could not be pure (always product new iterator).
23+
Result of Function.prototype.bind() could not be pure (because we can not substitute the required value of this).
24+
25+
It is supposed to use in reactive libraries.
26+
27+
## Examples
28+
```js
29+
var isPureFunction = require('is-pure-function');
30+
31+
function f(a, b) {
32+
return a + b;
33+
}
34+
// true
35+
isPureFunction(f, null, [1, 2]);
36+
37+
38+
var g = function(a) {
39+
return function(b) {
40+
return a + b;
41+
}
42+
}(1);
43+
// false (use closure var)
44+
isPureFunction(g, {}, [1, 2]);
45+
46+
47+
function getIndex(str, char) {
48+
return str.indexOf(char);
49+
}
50+
// false (wrong type of arguments)
51+
isPureFunction(getIndex, null, [1, 2]);
52+
// true
53+
isPureFunction(getIndex, null, ['str', 'c']);
54+
55+
56+
var f1 = function(a) {return a;}
57+
// false (extra arguments)
58+
isPureFunction(f1, undefined, [1, 2]);
59+
// false (not enough arguments)
60+
isPureFunction(f1, undefined, []);
61+
// true
62+
isPureFunction(f1, undefined, [1]);
63+
// throw ReferenceError, missing argument
64+
isPureFunction(f1, undefined);
65+
// false (not a function at all)
66+
isPureFunction({}, undefined, []);
67+
68+
69+
var getThisA = function() {
70+
return this.a;
71+
}
72+
// false (ReferenceError)
73+
isPureFunction(getThisA, null, []);
74+
// true (this -- context-argument of function)
75+
isPureFunction(getThisA, {}, []);
76+
77+
78+
function* generator() {
79+
return yield null;
80+
}
81+
// false
82+
isPureFunction(generator, 0, []);
83+
84+
85+
var arrow = (a, b) => a + b;
86+
// true
87+
isPureFunction(arrow, '', [1, 2]);
88+
89+
90+
var arrowThis = () => this;
91+
// false (this bound in arrow functions)
92+
isPureFunction(arrowThis, 0, []);
93+
94+
// but
95+
var arrowStr = () => 'this';
96+
//true
97+
isPureFunction(arrowStr, 0, []);
98+
99+
100+
var arrowArgs = () => arguments;
101+
// false (this bound in arrow functions)
102+
isPureFunction(arrowArgs, null, []);
103+
104+
// but
105+
var arrowComment = () => {
106+
// arguments
107+
return 3;
108+
}
109+
// true
110+
isPureFunction(arrowComment, null, []);
111+
112+
113+
var boundFn = function() {}.bind();
114+
// false (can not substitute the required value of this)
115+
isPureFunction(boundFn, 0, []);
116+
117+
// it is unlikely you will need
118+
isPureFunction.clearCache();
119+
```
120+
121+
Use pure functions for FRP (the best way is arrow functions, without this and arguments object, with a fixed number of arguments).
122+
123+
## Tests
124+
Standalone pages test/es3.html && test/es6.html (via Mocha). Install webpack and opener, build scripts, than run tests:
125+
```bash
126+
$ npm install
127+
$ npm run build
128+
$ npm test
129+
```
130+
131+
## License ##
132+
[MIT](LICENSE)
133+
134+
[license-image]: https://img.shields.io/badge/license-MIT-blue.svg "license-image"
135+
[dependencies-image]: https://img.shields.io/gemnasium/mathiasbynens/he.svg?maxAge=2592000 "dependencies-image"
136+
[npm-image]: https://img.shields.io/npm/v/is-pure-function.svg "npm-image"
137+
[npm-url]: https://www.npmjs.com/package/is-pure-function "is-pure-function"

build/build.js

Lines changed: 121 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/build.js.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "is-pure-function",
3+
"version": "0.1.6",
4+
"description": "Return true, if function is pure.",
5+
"main": "src/is-pure-function.js",
6+
"scripts": {
7+
"build": "./node_modules/webpack/bin/webpack.js",
8+
"test": "./node_modules/opener/opener.js ./test/es3.html && ./node_modules/opener/opener.js ./test/es6.html"
9+
},
10+
"keywords": [
11+
"check",
12+
"pure",
13+
"function",
14+
"reactive",
15+
"model"
16+
],
17+
"dependencies": {},
18+
"devDependencies": {
19+
"webpack": ">=1.0.0",
20+
"opener": "*"
21+
},
22+
"author": "uid-11222",
23+
"bugs": {
24+
"url": "https://github.com/uid-11222/is-pure-function/issues"
25+
},
26+
"license": "MIT",
27+
"homepage": "https://github.com/uid-11222/is-pure-function",
28+
"repository": {
29+
"type": "git",
30+
"url": "https://github.com/uid-11222/is-pure-function"
31+
}
32+
}

src/is-pure-function.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
'use strict';
2+
3+
module.exports = isPureFunction;
4+
5+
var cache = {},
6+
toString = isPureFunction.toString,
7+
Function = isPureFunction.constructor,
8+
reFunction = /^\s*function\b/,
9+
reGenerator = /^\s*(function)?\s*\*/,
10+
reBoundWords = /\bthis\b|\barguments\b/,
11+
reStringsOrComments =
12+
/"[^"]*"|'[^']*'|`[^`]*`|\/\/.*\s|\/\*.*\*\//g;
13+
14+
/**
15+
* Return true, if call fn.apply(thisArg, args)
16+
* in global scope does not throw exception.
17+
*
18+
* @param {function} fn
19+
* @param {*} thisArg
20+
* @param {Array} args
21+
* @return {boolean}
22+
*/
23+
function isPureFunction(fn, thisArg, args) {
24+
var code, pureFn;
25+
26+
if (args.length !== fn.length) return false;
27+
if (typeof fn !== 'function') return false;
28+
29+
try { code = toString.call(fn); }
30+
catch (e) { return false; }
31+
32+
pureFn = cache[code];
33+
if (!pureFn) {
34+
/* Maybe fn already cached as not a pure. */
35+
if (pureFn === null) return false;
36+
try {
37+
38+
if (reFunction.test(code)) {
39+
/* Generators could not be pure. */
40+
if (reGenerator.test(code)) return false;
41+
} else {
42+
/* Arrow function could not contain bound words. */
43+
if (reBoundWords.test(
44+
code.replace(reStringsOrComments, '')
45+
)) return false;
46+
}
47+
48+
pureFn = Function (
49+
'"use strict";return(' + code + ')'
50+
)();
51+
52+
} catch (e) { return false; }
53+
finally {
54+
cache[code] = pureFn || null;
55+
}
56+
}
57+
58+
try { pureFn.apply(thisArg, args); }
59+
catch (e) { return false; }
60+
61+
return true;
62+
}
63+
64+
/**
65+
* Сlear cache and delete links to all functions.
66+
* @memberof isPureFunction
67+
*/
68+
isPureFunction.clearCache = function clearCache() {
69+
for (var key in cache) cache[key] = undefined;
70+
};

0 commit comments

Comments
 (0)