property-expr
Advanced tools
Comparing version 1.4.0 to 1.5.0
134
index.js
/** | ||
* @license | ||
* expr 1.0.0 | ||
* Copyright 2014 Jason Quense | ||
* Based on Kendo UI Core expression code <https://github.com/telerik/kendo-ui-core#license-information> | ||
* Copyright :copyright: 2014 Telerik | ||
* Available under MIT license <https://github.com/theporchrat/expr/blob/master/LICENSE.txt> | ||
*/ | ||
'use strict' | ||
function Cache(maxSize) { | ||
this._maxSize = maxSize | ||
this.clear() | ||
} | ||
Cache.prototype.clear = function() { | ||
this._size = 0 | ||
this._values = {} | ||
} | ||
Cache.prototype.get = function(key) { | ||
return this._values[key] | ||
} | ||
Cache.prototype.set = function(key, value) { | ||
this._size >= this._maxSize && this.clear() | ||
if (!this._values.hasOwnProperty(key)) { | ||
this._size++ | ||
} | ||
return this._values[key] = value | ||
} | ||
var SPLIT_REGEX = /[^.^\]^[]+|(?=\[\]|\.\.)/g, | ||
DIGIT_REGEX = /^\d+$/, | ||
LEAD_DIGIT_REGEX = /^\d/, | ||
SPEC_CHAR_REGEX = /[~`!#$%\^&*+=\-\[\]\\';,/{}|\\":<>\?]/g | ||
SPEC_CHAR_REGEX = /[~`!#$%\^&*+=\-\[\]\\';,/{}|\\":<>\?]/g, | ||
CLEAN_QUOTES_REGEX = /^\s*(['"]?)(.*?)(\1)\s*$/, | ||
MAX_CACHE_SIZE = 512 | ||
var setCache = {}, | ||
getCache = {} | ||
var contentSecurityPolicy = false, | ||
pathCache = new Cache(MAX_CACHE_SIZE), | ||
setCache = new Cache(MAX_CACHE_SIZE), | ||
getCache = new Cache(MAX_CACHE_SIZE) | ||
try { | ||
new Function('') | ||
} catch (error) { | ||
contentSecurityPolicy = true | ||
} | ||
module.exports = { | ||
Cache: Cache, | ||
expr: expr, | ||
setter: function(path) { | ||
return ( | ||
setCache[path] || | ||
(setCache[path] = new Function( | ||
'data, value', | ||
expr(path, 'data') + ' = value' | ||
)) | ||
) | ||
}, | ||
split: split, | ||
getter: function(path, safe) { | ||
var k = path + '_' + safe | ||
return ( | ||
getCache[k] || | ||
(getCache[k] = new Function('data', 'return ' + expr(path, safe, 'data'))) | ||
) | ||
}, | ||
normalizePath: normalizePath, | ||
split: function(path) { | ||
return path.match(SPLIT_REGEX) | ||
}, | ||
setter: contentSecurityPolicy | ||
? function(path) { | ||
var parts = normalizePath(path) | ||
return function(data, value) { | ||
return setterFallback(parts, data, value) | ||
} | ||
} | ||
: function(path) { | ||
return setCache.get(path) || setCache.set( | ||
path, | ||
new Function( | ||
'data, value', | ||
expr(path, 'data') + ' = value' | ||
) | ||
) | ||
}, | ||
getter: contentSecurityPolicy | ||
? function(path, safe) { | ||
var parts = normalizePath(path) | ||
return function(data) { | ||
return getterFallback(parts, safe, data) | ||
} | ||
} | ||
: function(path, safe) { | ||
var key = path + '_' + safe | ||
return getCache.get(key) || getCache.set( | ||
key, | ||
new Function('data', 'return ' + expr(path, safe, 'data')) | ||
) | ||
}, | ||
join: function(segments) { | ||
@@ -55,6 +96,41 @@ return segments.reduce(function(path, part) { | ||
forEach: function(path, cb, thisArg) { | ||
forEach(path.match(SPLIT_REGEX), cb, thisArg) | ||
forEach(split(path), cb, thisArg) | ||
} | ||
} | ||
function setterFallback(parts, data, value) { | ||
var index = 0, | ||
len = parts.length | ||
while (index < len - 1) { | ||
data = data[parts[index++]] | ||
} | ||
data[parts[index]] = value | ||
} | ||
function getterFallback(parts, safe, data) { | ||
var index = 0, | ||
len = parts.length | ||
while (index < len) { | ||
if (data == null || !safe) { | ||
data = data[parts[index++]] | ||
} else { | ||
return | ||
} | ||
} | ||
return data | ||
} | ||
function normalizePath(path) { | ||
return pathCache.get(path) || pathCache.set( | ||
path, | ||
split(path).map(function(part) { | ||
return part.replace(CLEAN_QUOTES_REGEX, '$2') | ||
}) | ||
) | ||
} | ||
function split(path) { | ||
return path.match(SPLIT_REGEX) | ||
} | ||
function expr(expression, safe, param) { | ||
@@ -106,3 +182,3 @@ expression = expression || '' | ||
var result = param, | ||
parts = path.match(SPLIT_REGEX), | ||
parts = split(path), | ||
isLast | ||
@@ -109,0 +185,0 @@ |
{ | ||
"name": "property-expr", | ||
"version": "1.4.0", | ||
"version": "1.5.0", | ||
"description": "tiny util for getting and setting deep object props safely", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -24,7 +24,7 @@ expr | ||
setBaz(obj, 'set me!') | ||
console.log(foo.bar[1].buz.baz) // => 'set me!' | ||
console.log(obj.foo.bar[1].buz.baz) // => 'set me!' | ||
### `getter(expression, [ safeAccess ])` | ||
returns a function that accepts an obj and returns the value at the supplied expression. You can create a "safe" getter, which won't error out when accessing properties that don't exist, reducing existance checks befroe property access: | ||
Returns a function that accepts an obj and returns the value at the supplied expression. You can create a "safe" getter, which won't error out when accessing properties that don't exist, reducing existance checks befroe property access: | ||
@@ -36,3 +36,3 @@ expr.getter('foo.bar.baz', true)({ foo: {} }) // => undefined | ||
returns a function that accepts an obj and a value and sets the property pointed to by the expression to the supplied value. | ||
Returns a function that accepts an obj and a value and sets the property pointed to by the expression to the supplied value. | ||
@@ -42,3 +42,3 @@ | ||
Returns a normalized expression string pointing to a property on root object | ||
Returns a normalized expression string pointing to a property on root object | ||
`paramName`. | ||
@@ -53,6 +53,6 @@ | ||
```js | ||
split("foo['bar'][0].baz") // [ "foo", "'bar'", "0", "baz"] | ||
expr.split("foo['bar'][0].baz") // [ "foo", "'bar'", "0", "baz"] | ||
``` | ||
### `forEach(path, iterator[, thisArg]) ` | ||
### `forEach(path, iterator[, thisArg])` | ||
@@ -62,7 +62,29 @@ Iterate through a path but segment, with some additional helpful metadata about the segment. The iterator function is called with: `pathSegment`, `isBracket`, `isArray`, `idx`, `segments` | ||
```js | ||
.forEach('foo["bar"][1]', function(pathSegment, isBracket, isArray, idx, segments) { | ||
expr.forEach('foo["bar"][1]', function(pathSegment, isBracket, isArray, idx, segments) { | ||
// 'foo' -> isBracket = false, isArray = false, idx = 0 | ||
// '"bar"' -> isBracket = true, isArray = false, idx = 1 | ||
// '0' -> isBracket = false, isArray = true, idx = 2 | ||
} | ||
``` | ||
}) | ||
``` | ||
### `normalizePath(path)` | ||
Returns an array of path segments without quotes and spaces. | ||
```js | ||
expr.normalizePath('foo["bar"][ "1" ][2][ " sss " ]') | ||
// ['foo', 'bar', '1', '2', ' sss '] | ||
``` | ||
### `new Cache(maxSize)` | ||
Just an utility class, returns an instance of cache. When the max size is exceeded, cache clears its storage. | ||
```js | ||
var cache = new Cache(2) | ||
cache.set('a', 123) // returns 123 | ||
cache.get('a') // returns 123 | ||
cache.clear() | ||
cache.set('a', 1) | ||
cache.set('b', 2) // cache contains 2 values | ||
cache.set('c', 3) // cache was cleaned automatically and contains 1 value | ||
``` |
39
test.js
@@ -17,3 +17,3 @@ var a = require('assert'), | ||
//--- Getters ----------------------------------------------- | ||
// -- Getters -- | ||
a.strictEqual(getter('foo.fux')(obj), 5); | ||
@@ -26,3 +26,3 @@ a.deepEqual(getter('foo.bar')(obj), ['baz', 'bux']); | ||
//safe access | ||
// safe access | ||
a.strictEqual(getter('foo.fux', true)(obj), 5); | ||
@@ -45,3 +45,3 @@ a.deepEqual(getter('foo.bar', true)(obj), ['baz', 'bux']); | ||
//--- Setters ----------------------------------------------- | ||
// -- Setters -- | ||
setter('foo.fux')(obj, 10); | ||
@@ -56,4 +56,23 @@ a.strictEqual(obj.foo.fux, 10); | ||
// -- Split ------- | ||
// -- Cache -- | ||
var cache = new expression.Cache(3) | ||
a.strictEqual(cache._size, 0) | ||
a.strictEqual(cache.set('a', a), a) | ||
a.strictEqual(cache.get('a'), a) | ||
a.strictEqual(cache._size, 1) | ||
a.strictEqual(cache.set('b', 123), 123) | ||
a.strictEqual(cache.get('b'), 123) | ||
a.strictEqual(cache.set('b', 321), 321) | ||
a.strictEqual(cache.get('b'), 321) | ||
a.strictEqual(cache.set('c', null), null) | ||
a.strictEqual(cache.get('c'), null) | ||
a.strictEqual(cache._size, 3) | ||
a.strictEqual(cache.set('d', 444), 444) | ||
a.strictEqual(cache._size, 1) | ||
cache.clear() | ||
a.strictEqual(cache._size, 0) | ||
a.strictEqual(cache.get('a'), undefined) | ||
// -- split -- | ||
var parts = expression.split('foo.baz["bar"][1]'); | ||
@@ -63,3 +82,3 @@ | ||
// -- JOIN ------- | ||
// -- join -- | ||
@@ -72,3 +91,3 @@ var parts = expression.split('foo.baz["bar"][1]'); | ||
// -- ForEach ------ | ||
// -- forEach -- | ||
@@ -110,2 +129,10 @@ var count = 0; | ||
a.strictEqual(count, 3); | ||
// -- normalizePath -- | ||
a.deepEqual( | ||
expression.normalizePath('foo[ " bux\'s " ].bar["baz"][ 9 ][ \' s \' ]'), | ||
['foo', ' bux\'s ', 'bar', 'baz', '9', ' s '] | ||
) | ||
console.log('--- Tests Passed ---'); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
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
13324
299
86
0