Comparing version 2.2.1 to 2.3.0-rc1
# Changelog | ||
## v2.3.0 | ||
* Adding the `tree/cursor.clone` and the `tree/cursor.deepClone` methods. | ||
* Adding the `tree/cursor.pop` and the `tree/cursor.shift` methods. | ||
* Adding a way to disable a single monkey's immutability. | ||
* Fixing an issue where the `tree.commit` method would fire a useless update. | ||
* Fixing an issue related to updates and dynamic paths. | ||
* Fixing the `tree/cursor.splice` to correctly handle negative indexes. | ||
## v2.2.1 | ||
@@ -4,0 +13,0 @@ |
@@ -13,4 +13,2 @@ /** | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); | ||
@@ -175,3 +173,3 @@ | ||
['apply', 'concat', 'deepMerge', 'exists', 'get', 'push', 'merge', 'project', 'serialize', 'set', 'splice', 'unset', 'unshift'].forEach(bootstrap); | ||
['apply', 'clone', 'concat', 'deepClone', 'deepMerge', 'exists', 'get', 'push', 'merge', 'pop', 'project', 'serialize', 'set', 'shift', 'splice', 'unset', 'unshift'].forEach(bootstrap); | ||
@@ -188,3 +186,3 @@ // Registering the initial monkeys | ||
/** | ||
* Creating statics | ||
* Monkey helper. | ||
*/ | ||
@@ -237,7 +235,7 @@ | ||
if (data instanceof _monkey.MonkeyDefinition || data instanceof _monkey.Monkey) { | ||
var monkey = new _monkey.Monkey(_this2, p, data instanceof _monkey.Monkey ? data.definition : data); | ||
var monkeyInstance = new _monkey.Monkey(_this2, p, data instanceof _monkey.Monkey ? data.definition : data); | ||
register.push(monkey); | ||
register.push(monkeyInstance); | ||
(0, _update3['default'])(_this2._monkeys, p, { type: 'set', value: monkey }, { | ||
(0, _update3['default'])(_this2._monkeys, p, { type: 'set', value: monkeyInstance }, { | ||
immutable: false, | ||
@@ -435,3 +433,3 @@ persistent: false, | ||
this._affectedPathsIndex[hash] = true; | ||
this._transaction.push(_extends({}, operation, { path: affectedPath })); | ||
this._transaction.push(shallowMerge({}, operation, { path: affectedPath })); | ||
@@ -471,2 +469,5 @@ // Updating the monkeys | ||
// Do not fire update if the transaction is empty | ||
if (!this._transaction.length) return this; | ||
// Clearing timeout if one was defined | ||
@@ -576,3 +577,3 @@ if (this._future) this._future = clearTimeout(this._future); | ||
if (args.length === 1) return new _monkey.MonkeyDefinition(args[0]); | ||
if (args.length === 1 && typeof args[0] !== 'function') return new _monkey.MonkeyDefinition(args[0]); | ||
@@ -595,10 +596,3 @@ return new _monkey.MonkeyDefinition(args); | ||
*/ | ||
Object.defineProperty(Baobab, 'version', { | ||
value: '2.2.1' | ||
}); | ||
/** | ||
* Exporting | ||
*/ | ||
exports['default'] = Baobab; | ||
Baobab.VERSION = '2.3.0-rc1'; | ||
module.exports = exports['default']; |
@@ -498,2 +498,40 @@ /** | ||
/** | ||
* Method used to shallow clone data from the tree. | ||
* | ||
* Arity (1): | ||
* @param {path} path - Path to get in the tree. | ||
* | ||
* Arity (2): | ||
* @param {..step} path - Path to get in the tree. | ||
* | ||
* @return {mixed} - Cloned data at path. | ||
*/ | ||
}, { | ||
key: 'clone', | ||
value: function clone() { | ||
var data = this.get.apply(this, arguments); | ||
return (0, _helpers.shallowClone)(data); | ||
} | ||
/** | ||
* Method used to deep clone data from the tree. | ||
* | ||
* Arity (1): | ||
* @param {path} path - Path to get in the tree. | ||
* | ||
* Arity (2): | ||
* @param {..step} path - Path to get in the tree. | ||
* | ||
* @return {mixed} - Cloned data at path. | ||
*/ | ||
}, { | ||
key: 'deepClone', | ||
value: function deepClone() { | ||
var data = this.get.apply(this, arguments); | ||
return (0, _helpers.deepClone)(data); | ||
} | ||
/** | ||
* Method used to return raw data from the tree, by carefully avoiding | ||
@@ -766,2 +804,9 @@ * computed one. | ||
// Not using a Set so that ES5 consumers don't pay a bundle size price | ||
var INTRANSITIVE_SETTERS = { | ||
unset: true, | ||
pop: true, | ||
shift: true | ||
}; | ||
/** | ||
@@ -801,3 +846,3 @@ * Function creating a setter method for the Cursor class. | ||
// Handling arities | ||
if (arguments.length === 1 && name !== 'unset') { | ||
if (arguments.length === 1 && !INTRANSITIVE_SETTERS[name]) { | ||
value = path; | ||
@@ -816,2 +861,5 @@ path = []; | ||
// Checking the solvability of the cursor's dynamic path | ||
if (!this.solvedPath) throw (0, _helpers.makeError)('Baobab.Cursor.' + name + ': the dynamic path of the cursor cannot be solved.', { path: this.path }); | ||
var fullPath = this.solvedPath.concat(path); | ||
@@ -836,2 +884,4 @@ | ||
makeSetter('unshift'); | ||
makeSetter('pop'); | ||
makeSetter('shift'); | ||
makeSetter('splice', _type2['default'].splicer); | ||
@@ -838,0 +888,0 @@ makeSetter('merge', _type2['default'].object); |
@@ -566,10 +566,14 @@ /* eslint eqeqeq: 0 */ | ||
* | ||
* @param {array} array - The array to splice. | ||
* @param {integer} startIndex - The start index. | ||
* @param {integer} nb - Number of elements to remove. | ||
* @param {...mixed} elements - Elements to append after splicing. | ||
* @return {array} - The spliced array. | ||
* @param {array} array - The array to splice. | ||
* @param {integer} startIndex - The start index. | ||
* @param {integer} nb - Number of elements to remove. | ||
* @param {...mixed} elements - Elements to append after splicing. | ||
* @return {array} - The spliced array. | ||
*/ | ||
function splice(array, startIndex, nb) { | ||
nb = Math.max(0, nb); | ||
// Positive index | ||
for (var _len2 = arguments.length, elements = Array(_len2 > 3 ? _len2 - 3 : 0), _key2 = 3; _key2 < _len2; _key2++) { | ||
@@ -579,3 +583,6 @@ elements[_key2 - 3] = arguments[_key2]; | ||
return array.slice(0, startIndex).concat(elements).concat(array.slice(startIndex + Math.max(0, nb))); | ||
if (startIndex >= 0) return array.slice(0, startIndex).concat(elements).concat(array.slice(startIndex + nb)); | ||
// Negative index | ||
return array.slice(0, array.length + startIndex).concat(elements).concat(array.slice(array.length + startIndex + nb)); | ||
} | ||
@@ -582,0 +589,0 @@ |
@@ -55,6 +55,16 @@ /** | ||
}); | ||
this.options = definition.options || {}; | ||
} else { | ||
this.getter = definition[definition.length - 1]; | ||
this.projection = definition.slice(0, -1); | ||
var offset = 1, | ||
options = {}; | ||
if (_type2['default'].object(definition[definition.length - 1])) { | ||
offset++; | ||
options = definition[definition.length - 1]; | ||
} | ||
this.getter = definition[definition.length - offset]; | ||
this.projection = definition.slice(0, -offset); | ||
this.paths = this.projection; | ||
this.options = options; | ||
} | ||
@@ -210,4 +220,3 @@ | ||
// Freezing if required | ||
if (tree.options.immutable) (0, _helpers.deepFreeze)(cache); | ||
if (tree.options.immutable && def.options.immutable !== false) (0, _helpers.deepFreeze)(cache); | ||
@@ -223,3 +232,3 @@ alreadyComputed = true; | ||
// If the tree does not accept lazy monkeys, we solve the lazy getter | ||
// Should we write the lazy getter in the tree or solve it right now? | ||
if (this.tree.options.lazyMonkeys) { | ||
@@ -226,0 +235,0 @@ this.tree._data = (0, _update3['default'])(this.tree._data, this.path, { type: 'monkey', value: lazyGetter }, this.tree.options).data; |
@@ -209,3 +209,7 @@ /** | ||
} else if (type.array(definition)) { | ||
if (!type['function'](definition[definition.length - 1]) || !definition.slice(0, -1).every(function (p) { | ||
var offset = 1; | ||
if (type.object(definition[definition.length - 1])) offset++; | ||
if (!type['function'](definition[definition.length - offset]) || !definition.slice(0, -offset).every(function (p) { | ||
return type.path(p); | ||
@@ -240,3 +244,3 @@ })) return null; | ||
// Ordered by likeliness | ||
var VALID_OPERATIONS = ['set', 'apply', 'push', 'unshift', 'concat', 'deepMerge', 'merge', 'splice', 'unset']; | ||
var VALID_OPERATIONS = ['set', 'apply', 'push', 'unshift', 'concat', 'pop', 'shift', 'deepMerge', 'merge', 'splice', 'unset']; | ||
@@ -243,0 +247,0 @@ type.operationType = function (string) { |
@@ -159,26 +159,44 @@ /** | ||
/** | ||
* Unset | ||
* Pop | ||
*/ | ||
else if (operationType === 'unset') { | ||
if (_type2['default'].object(p)) delete p[s];else if (_type2['default'].array(p)) p.splice(s, 1); | ||
else if (operationType === 'pop') { | ||
if (!_type2['default'].array(p[s])) throw err('pop', 'array', currentPath); | ||
if (opts.persistent) p[s] = (0, _helpers.splice)(p[s], -1, 1);else p[s].pop(); | ||
} | ||
/** | ||
* Merge | ||
* Shift | ||
*/ | ||
else if (operationType === 'merge') { | ||
if (!_type2['default'].object(p[s])) throw err('merge', 'object', currentPath); | ||
else if (operationType === 'shift') { | ||
if (!_type2['default'].array(p[s])) throw err('shift', 'array', currentPath); | ||
if (opts.persistent) p[s] = (0, _helpers.shallowMerge)({}, p[s], value);else p[s] = (0, _helpers.shallowMerge)(p[s], value); | ||
if (opts.persistent) p[s] = (0, _helpers.splice)(p[s], 0, 1);else p[s].shift(); | ||
} | ||
/** | ||
* Deep merge | ||
* Unset | ||
*/ | ||
else if (operationType === 'deepMerge') { | ||
if (!_type2['default'].object(p[s])) throw err('deepMerge', 'object', currentPath); | ||
if (opts.persistent) p[s] = (0, _helpers.deepMerge)({}, p[s], value);else p[s] = (0, _helpers.deepMerge)(p[s], value); | ||
else if (operationType === 'unset') { | ||
if (_type2['default'].object(p)) delete p[s];else if (_type2['default'].array(p)) p.splice(s, 1); | ||
} | ||
/** | ||
* Merge | ||
*/ | ||
else if (operationType === 'merge') { | ||
if (!_type2['default'].object(p[s])) throw err('merge', 'object', currentPath); | ||
if (opts.persistent) p[s] = (0, _helpers.shallowMerge)({}, p[s], value);else p[s] = (0, _helpers.shallowMerge)(p[s], value); | ||
} | ||
/** | ||
* Deep merge | ||
*/ | ||
else if (operationType === 'deepMerge') { | ||
if (!_type2['default'].object(p[s])) throw err('deepMerge', 'object', currentPath); | ||
if (opts.persistent) p[s] = (0, _helpers.deepMerge)({}, p[s], value);else p[s] = (0, _helpers.deepMerge)(p[s], value); | ||
} | ||
if (opts.immutable) (0, _helpers.deepFreeze)(p); | ||
@@ -185,0 +203,0 @@ |
The MIT License (MIT) | ||
Copyright (c) 2014-2015 Guillaume Plique (Yomguithereal) | ||
Copyright (c) 2014-2016 Guillaume Plique (Yomguithereal) | ||
@@ -5,0 +5,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy |
{ | ||
"name": "baobab", | ||
"version": "2.2.1", | ||
"version": "2.3.0-rc1", | ||
"description": "JavaScript persistent data tree with cursors.", | ||
@@ -10,2 +10,3 @@ "main": "./dist/baobab.js", | ||
"devDependencies": { | ||
"add-banner": "^0.1.0", | ||
"async": "^1.2.1", | ||
@@ -19,17 +20,14 @@ "babel": "^5.6.14", | ||
"eslint-config-airbnb": "^1.0.0", | ||
"gulp": "^3.8.10", | ||
"gulp-header": "^1.2.2", | ||
"gulp-rename": "^1.2.2", | ||
"gulp-replace": "^0.5.3", | ||
"gulp-uglify": "^1.0.2", | ||
"lodash": "^3.6.0", | ||
"mkdirp": "^0.5.1", | ||
"mocha": "^2.0.1", | ||
"vinyl-buffer": "^1.0.0", | ||
"vinyl-source-stream": "^1.1.0" | ||
"uglify-js": "^2.6.1" | ||
}, | ||
"scripts": { | ||
"benchmark": "babel-node benchmark.js", | ||
"build": "gulp build && babel ./src --out-dir dist", | ||
"build": "mkdirp build && browserify ./src/baobab.js -t [babelify --loose all] -s Baobab -o ./build/baobab.js && uglifyjs ./build/baobab.js -c -m -o ./build/baobab.min.js && node ./scripts/banner.js", | ||
"check": "npm test && npm run lint && npm run build", | ||
"dist": "babel ./src --out-dir dist", | ||
"lint": "eslint ./src ./test", | ||
"prepublish": "npm run build", | ||
"prepublish": "npm run dist", | ||
"test": "mocha -R spec --compilers js:babel/register ./test/endpoint.js" | ||
@@ -36,0 +34,0 @@ }, |
@@ -239,5 +239,8 @@ [![Build Status](https://travis-ci.org/Yomguithereal/baobab.svg)](https://travis-ci.org/Yomguithereal/baobab) | ||
// Applying splice n times with different arguments | ||
var newArray = cursor.splice([[1, 2], [3, 2, 'hello']]); | ||
// Inserting an item | ||
var newArray = cursor.splice([1, 0, 'newItem']); | ||
// Inserting multiple items | ||
var newArray = cursor.splice([1, 0, 'newItem1', 'newItem2']); | ||
// At key | ||
@@ -575,2 +578,33 @@ var newArray = cursor.splice('list', [1, 1]) | ||
// Possibility to disable a single monkey's immutability | ||
var tree = new Baobab({ | ||
data: { | ||
users: ['Jack', 'John'], | ||
onlyJack: monkey({ | ||
cursors: { | ||
users: ['data', 'users'], | ||
get: function(data) { | ||
return data.users.filter(function(user) { | ||
return user === 'Jack'; | ||
}); | ||
}, | ||
options: { | ||
immutable: false | ||
} | ||
} | ||
}), | ||
// Using the shorthand | ||
onlyJohn: monkey( | ||
['data', 'users'], | ||
function(users) { | ||
return users.filter(function(user) { | ||
return user === 'John'; | ||
}); | ||
}, | ||
{immutable: false} | ||
) | ||
} | ||
}); | ||
// Finally, know that you can use relative paths for convenience | ||
@@ -932,2 +966,3 @@ var tree = new Baobab({ | ||
cursor.release(); | ||
watcher.release(); | ||
``` | ||
@@ -934,0 +969,0 @@ |
@@ -137,3 +137,5 @@ /** | ||
'apply', | ||
'clone', | ||
'concat', | ||
'deepClone', | ||
'deepMerge', | ||
@@ -144,5 +146,7 @@ 'exists', | ||
'merge', | ||
'pop', | ||
'project', | ||
'serialize', | ||
'set', | ||
'shift', | ||
'splice', | ||
@@ -201,3 +205,3 @@ 'unset', | ||
data instanceof Monkey) { | ||
const monkey = new Monkey( | ||
const monkeyInstance = new Monkey( | ||
this, | ||
@@ -208,5 +212,5 @@ p, | ||
register.push(monkey); | ||
register.push(monkeyInstance); | ||
update(this._monkeys, p, {type: 'set', value: monkey}, { | ||
update(this._monkeys, p, {type: 'set', value: monkeyInstance}, { | ||
immutable: false, | ||
@@ -417,3 +421,3 @@ persistent: false, | ||
this._affectedPathsIndex[hash] = true; | ||
this._transaction.push({...operation, path: affectedPath}); | ||
this._transaction.push(shallowMerge({}, operation, {path: affectedPath})); | ||
@@ -451,2 +455,6 @@ // Updating the monkeys | ||
// Do not fire update if the transaction is empty | ||
if (!this._transaction.length) | ||
return this; | ||
// Clearing timeout if one was defined | ||
@@ -543,3 +551,3 @@ if (this._future) | ||
/** | ||
* Creating statics | ||
* Monkey helper. | ||
*/ | ||
@@ -551,3 +559,3 @@ Baobab.monkey = function(...args) { | ||
if (args.length === 1) | ||
if (args.length === 1 && typeof args[0] !== 'function') | ||
return new MonkeyDefinition(args[0]); | ||
@@ -571,10 +579,2 @@ | ||
*/ | ||
Object.defineProperty(Baobab, 'version', { | ||
value: '2.2.1' | ||
}); | ||
/** | ||
* Exporting | ||
*/ | ||
export default Baobab; | ||
Baobab.VERSION = '2.3.0-rc1'; |
@@ -18,2 +18,3 @@ /** | ||
makeError, | ||
shallowClone, | ||
solveUpdate | ||
@@ -464,2 +465,36 @@ } from './helpers'; | ||
/** | ||
* Method used to shallow clone data from the tree. | ||
* | ||
* Arity (1): | ||
* @param {path} path - Path to get in the tree. | ||
* | ||
* Arity (2): | ||
* @param {..step} path - Path to get in the tree. | ||
* | ||
* @return {mixed} - Cloned data at path. | ||
*/ | ||
clone(...args) { | ||
const data = this.get(...args); | ||
return shallowClone(data); | ||
} | ||
/** | ||
* Method used to deep clone data from the tree. | ||
* | ||
* Arity (1): | ||
* @param {path} path - Path to get in the tree. | ||
* | ||
* Arity (2): | ||
* @param {..step} path - Path to get in the tree. | ||
* | ||
* @return {mixed} - Cloned data at path. | ||
*/ | ||
deepClone(...args) { | ||
const data = this.get(...args); | ||
return deepClone(data); | ||
} | ||
/** | ||
* Method used to return raw data from the tree, by carefully avoiding | ||
@@ -730,2 +765,9 @@ * computed one. | ||
// Not using a Set so that ES5 consumers don't pay a bundle size price | ||
const INTRANSITIVE_SETTERS = { | ||
unset: true, | ||
pop: true, | ||
shift: true | ||
}; | ||
/** | ||
@@ -766,3 +808,3 @@ * Function creating a setter method for the Cursor class. | ||
// Handling arities | ||
if (arguments.length === 1 && name !== 'unset') { | ||
if (arguments.length === 1 && !INTRANSITIVE_SETTERS[name]) { | ||
value = path; | ||
@@ -783,2 +825,9 @@ path = []; | ||
// Checking the solvability of the cursor's dynamic path | ||
if (!this.solvedPath) | ||
throw makeError( | ||
`Baobab.Cursor.${name}: the dynamic path of the cursor cannot be solved.`, | ||
{path: this.path} | ||
); | ||
const fullPath = this.solvedPath.concat(path); | ||
@@ -806,4 +855,6 @@ | ||
makeSetter('unshift'); | ||
makeSetter('pop'); | ||
makeSetter('shift'); | ||
makeSetter('splice', type.splicer); | ||
makeSetter('merge', type.object); | ||
makeSetter('deepMerge', type.object); |
@@ -549,13 +549,23 @@ /* eslint eqeqeq: 0 */ | ||
* | ||
* @param {array} array - The array to splice. | ||
* @param {integer} startIndex - The start index. | ||
* @param {integer} nb - Number of elements to remove. | ||
* @param {...mixed} elements - Elements to append after splicing. | ||
* @return {array} - The spliced array. | ||
* @param {array} array - The array to splice. | ||
* @param {integer} startIndex - The start index. | ||
* @param {integer} nb - Number of elements to remove. | ||
* @param {...mixed} elements - Elements to append after splicing. | ||
* @return {array} - The spliced array. | ||
*/ | ||
export function splice(array, startIndex, nb, ...elements) { | ||
nb = Math.max(0, nb); | ||
// Positive index | ||
if (startIndex >= 0) | ||
return array | ||
.slice(0, startIndex) | ||
.concat(elements) | ||
.concat(array.slice(startIndex + nb)); | ||
// Negative index | ||
return array | ||
.slice(0, startIndex) | ||
.slice(0, array.length + startIndex) | ||
.concat(elements) | ||
.concat(array.slice(startIndex + Math.max(0, nb))); | ||
.concat(array.slice(array.length + startIndex + nb)); | ||
} | ||
@@ -562,0 +572,0 @@ |
@@ -42,7 +42,17 @@ /** | ||
.map(k => this.projection[k]); | ||
this.options = definition.options || {}; | ||
} | ||
else { | ||
this.getter = definition[definition.length - 1]; | ||
this.projection = definition.slice(0, -1); | ||
let offset = 1, | ||
options = {}; | ||
if (type.object(definition[definition.length - 1])) { | ||
offset++; | ||
options = definition[definition.length - 1]; | ||
} | ||
this.getter = definition[definition.length - offset]; | ||
this.projection = definition.slice(0, -offset); | ||
this.paths = this.projection; | ||
this.options = options; | ||
} | ||
@@ -191,4 +201,3 @@ | ||
// Freezing if required | ||
if (tree.options.immutable) | ||
if (tree.options.immutable && def.options.immutable !== false) | ||
deepFreeze(cache); | ||
@@ -205,3 +214,3 @@ | ||
// If the tree does not accept lazy monkeys, we solve the lazy getter | ||
// Should we write the lazy getter in the tree or solve it right now? | ||
if (this.tree.options.lazyMonkeys) { | ||
@@ -208,0 +217,0 @@ this.tree._data = update( |
@@ -213,4 +213,9 @@ /** | ||
else if (type.array(definition)) { | ||
if (!type.function(definition[definition.length - 1]) || | ||
!definition.slice(0, -1).every(p => type.path(p))) | ||
let offset = 1; | ||
if (type.object(definition[definition.length - 1])) | ||
offset++; | ||
if (!type.function(definition[definition.length - offset]) || | ||
!definition.slice(0, -offset).every(p => type.path(p))) | ||
return null; | ||
@@ -249,2 +254,4 @@ | ||
'concat', | ||
'pop', | ||
'shift', | ||
'deepMerge', | ||
@@ -251,0 +258,0 @@ 'merge', |
@@ -193,2 +193,36 @@ /** | ||
/** | ||
* Pop | ||
*/ | ||
else if (operationType === 'pop') { | ||
if (!type.array(p[s])) | ||
throw err( | ||
'pop', | ||
'array', | ||
currentPath | ||
); | ||
if (opts.persistent) | ||
p[s] = splice(p[s], -1, 1); | ||
else | ||
p[s].pop(); | ||
} | ||
/** | ||
* Shift | ||
*/ | ||
else if (operationType === 'shift') { | ||
if (!type.array(p[s])) | ||
throw err( | ||
'shift', | ||
'array', | ||
currentPath | ||
); | ||
if (opts.persistent) | ||
p[s] = splice(p[s], 0, 1); | ||
else | ||
p[s].shift(); | ||
} | ||
/** | ||
* Unset | ||
@@ -195,0 +229,0 @@ */ |
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
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
196093
13
21
4889
1014
1
1