set-value
Advanced tools
Comparing version 2.0.0 to 3.0.0
125
index.js
/*! | ||
* set-value <https://github.com/jonschlinkert/set-value> | ||
* | ||
* Copyright (c) 2014-2015, 2017, Jon Schlinkert. | ||
* Copyright (c) 2014-2018, Jon Schlinkert. | ||
* Released under the MIT License. | ||
@@ -10,43 +10,108 @@ */ | ||
var split = require('split-string'); | ||
var extend = require('extend-shallow'); | ||
var isPlainObject = require('is-plain-object'); | ||
var isObject = require('is-extendable'); | ||
const isPlain = require('is-plain-object'); | ||
module.exports = function(obj, prop, val) { | ||
if (!isObject(obj)) { | ||
return obj; | ||
function set(target, path, value, options) { | ||
if (!isObject(target)) { | ||
return target; | ||
} | ||
if (Array.isArray(prop)) { | ||
prop = [].concat.apply([], prop).join('.'); | ||
let opts = options || {}; | ||
const isArray = Array.isArray(path); | ||
if (!isArray && typeof path !== 'string') { | ||
return target; | ||
} | ||
if (typeof prop !== 'string') { | ||
return obj; | ||
let merge = opts.merge; | ||
if (merge && typeof merge !== 'function') { | ||
merge = Object.assign; | ||
} | ||
var keys = split(prop, {sep: '.', brackets: true}); | ||
var len = keys.length; | ||
var idx = -1; | ||
var current = obj; | ||
const keys = isArray ? path : split(path, opts); | ||
const len = keys.length; | ||
const orig = target; | ||
while (++idx < len) { | ||
var key = keys[idx]; | ||
if (idx !== len - 1) { | ||
if (!isObject(current[key])) { | ||
current[key] = {}; | ||
} | ||
current = current[key]; | ||
continue; | ||
if (!options && keys.length === 1) { | ||
result(target, keys[0], value, merge); | ||
return target; | ||
} | ||
for (let i = 0; i < len; i++) { | ||
let prop = keys[i]; | ||
if (!isObject(target[prop])) { | ||
target[prop] = {}; | ||
} | ||
if (isPlainObject(current[key]) && isPlainObject(val)) { | ||
current[key] = extend({}, current[key], val); | ||
} else { | ||
current[key] = val; | ||
if (i === len - 1) { | ||
result(target, prop, value, merge); | ||
break; | ||
} | ||
target = target[prop]; | ||
} | ||
return obj; | ||
}; | ||
return orig; | ||
} | ||
function result(target, path, value, merge) { | ||
if (merge && isPlain(target[path]) && isPlain(value)) { | ||
target[path] = merge({}, target[path], value); | ||
} else { | ||
target[path] = value; | ||
} | ||
} | ||
function split(path, options) { | ||
const id = createKey(path, options); | ||
if (set.memo[id]) return set.memo[id]; | ||
const char = (options && options.separator) ? options.separator : '.'; | ||
let keys = []; | ||
let res = []; | ||
if (options && typeof options.split === 'function') { | ||
keys = options.split(path); | ||
} else { | ||
keys = path.split(char); | ||
} | ||
for (let i = 0; i < keys.length; i++) { | ||
let prop = keys[i]; | ||
while (prop && prop.slice(-1) === '\\' && keys[i + 1]) { | ||
prop = prop.slice(0, -1) + char + keys[++i]; | ||
} | ||
res.push(prop); | ||
} | ||
set.memo[id] = res; | ||
return res; | ||
} | ||
function createKey(pattern, options) { | ||
let id = pattern; | ||
if (typeof options === 'undefined') { | ||
return id + ''; | ||
} | ||
const keys = Object.keys(options); | ||
for (let i = 0; i < keys.length; i++) { | ||
const key = keys[i]; | ||
id += ';' + key + '=' + String(options[key]); | ||
} | ||
return id; | ||
} | ||
function isObject(val) { | ||
switch (typeof val) { | ||
case 'null': | ||
return false; | ||
case 'object': | ||
return true; | ||
case 'function': | ||
return true; | ||
default: { | ||
return false; | ||
} | ||
} | ||
} | ||
set.memo = {}; | ||
module.exports = set; |
{ | ||
"name": "set-value", | ||
"description": "Create nested values and any intermediaries using dot notation (`'a.b.c'`) paths.", | ||
"version": "2.0.0", | ||
"version": "3.0.0", | ||
"homepage": "https://github.com/jonschlinkert/set-value", | ||
@@ -22,3 +22,3 @@ "author": "Jon Schlinkert (https://github.com/jonschlinkert)", | ||
"engines": { | ||
"node": ">=0.10.0" | ||
"node": ">=6.0" | ||
}, | ||
@@ -29,13 +29,35 @@ "scripts": { | ||
"dependencies": { | ||
"extend-shallow": "^2.0.1", | ||
"is-extendable": "^0.1.1", | ||
"is-plain-object": "^2.0.3", | ||
"split-string": "^3.0.1" | ||
"is-plain-object": "^2.0.4" | ||
}, | ||
"devDependencies": { | ||
"gulp-format-md": "^0.1.12", | ||
"mocha": "^3.4.2" | ||
"benchmarked": "^2.0.0", | ||
"deep-object": "^1.0.0", | ||
"deep-property": "^1.1.0", | ||
"deep-set": "^1.0.1", | ||
"deephas": "^1.0.5", | ||
"dot-prop": "^4.2.0", | ||
"dot2val": "^1.2.2", | ||
"es5-dot-prop": "^4.1.1", | ||
"gulp-format-md": "^1.0.0", | ||
"lodash.set": "^4.3.2", | ||
"minimist": "^1.2.0", | ||
"mocha": "^3.5.3", | ||
"object-path-set": "^1.0.0", | ||
"object-set": "^1.0.1", | ||
"split-string": "^5.0.4", | ||
"write": "^1.0.3" | ||
}, | ||
"keywords": [ | ||
"bury", | ||
"deep-get-set", | ||
"deep-object", | ||
"deep-property", | ||
"deep-set", | ||
"deep-set-in", | ||
"deephas", | ||
"dot-prop", | ||
"dot2val", | ||
"es5-dot-prop", | ||
"get", | ||
"getsetdeep", | ||
"has", | ||
@@ -45,5 +67,9 @@ "hasown", | ||
"keys", | ||
"lodash.set", | ||
"nested", | ||
"notation", | ||
"object", | ||
"object-path", | ||
"object-path-set", | ||
"object-set", | ||
"prop", | ||
@@ -54,2 +80,6 @@ "properties", | ||
"set", | ||
"set-deep", | ||
"set-deep-prop", | ||
"set-nested-prop", | ||
"setvalue", | ||
"value", | ||
@@ -81,4 +111,25 @@ "values" | ||
"reflinks": true | ||
} | ||
}, | ||
"reflinks": [ | ||
"bury", | ||
"deep-get-set", | ||
"deep-object", | ||
"deep-property", | ||
"deep-set", | ||
"deep-set-in", | ||
"deephas", | ||
"dot-prop", | ||
"dot2val", | ||
"es5-dot-prop", | ||
"getsetdeep", | ||
"lodash.set", | ||
"object-path", | ||
"object-path-set", | ||
"object-set", | ||
"set-deep", | ||
"set-deep-prop", | ||
"set-nested-prop", | ||
"setvalue" | ||
] | ||
} | ||
} |
180
README.md
@@ -5,2 +5,4 @@ # set-value [![NPM version](https://img.shields.io/npm/v/set-value.svg?style=flat)](https://www.npmjs.com/package/set-value) [![NPM monthly downloads](https://img.shields.io/npm/dm/set-value.svg?style=flat)](https://npmjs.org/package/set-value) [![NPM total downloads](https://img.shields.io/npm/dt/set-value.svg?style=flat)](https://npmjs.org/package/set-value) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/set-value.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/set-value) | ||
Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support. | ||
## Install | ||
@@ -52,37 +54,107 @@ | ||
**Escaping with double-quotes or single-quotes** | ||
## Benchmarks | ||
Wrap double or single quotes around the string, or part of the string, that should not be split by set-value: | ||
_(benchmarks were run on a MacBook Pro 2.5 GHz Intel Core i7, 16 GB 1600 MHz DDR3)_. | ||
```js | ||
console.log(set({}, '"a.b".c', 'd')); | ||
//=> { 'a.b': { c: 'd' } } | ||
set-value is more reliable and has more features than dot-prop, without sacrificing performance. | ||
console.log(set({}, "'a.b'.c", "d")); | ||
//=> { 'a.b': { c: 'd' } } | ||
console.log(set({}, '"this/is/a/.file.path"', 'd')); | ||
//=> { 'this/is/a/file.path': 'd' } | ||
``` | ||
# deep (194 bytes) | ||
deep-object x 629,744 ops/sec ±0.85% (88 runs sampled) | ||
deep-property x 1,470,427 ops/sec ±0.94% (89 runs sampled) | ||
deep-set x 1,401,089 ops/sec ±1.02% (91 runs sampled) | ||
deephas x 590,005 ops/sec ±1.73% (86 runs sampled) | ||
dot-prop x 1,261,408 ops/sec ±0.94% (90 runs sampled) | ||
dot2val x 1,672,729 ops/sec ±1.12% (89 runs sampled) | ||
es5-dot-prop x 1,313,018 ops/sec ±0.79% (91 runs sampled) | ||
lodash-set x 1,074,464 ops/sec ±0.97% (93 runs sampled) | ||
object-path-set x 961,198 ops/sec ±2.07% (74 runs sampled) | ||
object-set x 258,438 ops/sec ±0.69% (90 runs sampled) | ||
set-value x 1,976,843 ops/sec ±2.07% (89 runs sampled) | ||
### Bracket support | ||
fastest is set-value (by 186% avg) | ||
set-value does not split inside brackets or braces: | ||
# medium (98 bytes) | ||
deep-object x 3,249,287 ops/sec ±1.04% (93 runs sampled) | ||
deep-property x 3,409,307 ops/sec ±1.28% (88 runs sampled) | ||
deep-set x 3,240,776 ops/sec ±1.13% (93 runs sampled) | ||
deephas x 960,504 ops/sec ±1.39% (89 runs sampled) | ||
dot-prop x 2,776,388 ops/sec ±0.80% (94 runs sampled) | ||
dot2val x 3,889,791 ops/sec ±1.28% (91 runs sampled) | ||
es5-dot-prop x 2,779,604 ops/sec ±1.32% (91 runs sampled) | ||
lodash-set x 2,791,304 ops/sec ±0.75% (90 runs sampled) | ||
object-path-set x 2,462,084 ops/sec ±1.51% (91 runs sampled) | ||
object-set x 838,569 ops/sec ±0.87% (90 runs sampled) | ||
set-value x 4,767,287 ops/sec ±1.21% (91 runs sampled) | ||
```js | ||
console.log(set({}, '[a.b].c', 'd')); | ||
//=> { '[a.b]': { c: 'd' } } | ||
fastest is set-value (by 181% avg) | ||
console.log(set({}, "(a.b).c", "d")); | ||
//=> { '(a.b)': { c: 'd' } } | ||
# shallow (101 bytes) | ||
deep-object x 4,793,168 ops/sec ±0.75% (88 runs sampled) | ||
deep-property x 4,669,218 ops/sec ±1.17% (90 runs sampled) | ||
deep-set x 4,648,247 ops/sec ±0.73% (91 runs sampled) | ||
deephas x 1,246,414 ops/sec ±1.67% (92 runs sampled) | ||
dot-prop x 3,913,694 ops/sec ±1.23% (89 runs sampled) | ||
dot2val x 5,428,829 ops/sec ±0.76% (92 runs sampled) | ||
es5-dot-prop x 3,897,931 ops/sec ±1.19% (92 runs sampled) | ||
lodash-set x 6,128,638 ops/sec ±0.95% (87 runs sampled) | ||
object-path-set x 5,429,978 ops/sec ±3.31% (87 runs sampled) | ||
object-set x 1,529,485 ops/sec ±2.37% (89 runs sampled) | ||
set-value x 7,150,921 ops/sec ±1.58% (89 runs sampled) | ||
console.log(set({}, "<a.b>.c", "d")); | ||
//=> { '<a.b>': { c: 'd' } } | ||
fastest is set-value (by 172% avg) | ||
console.log(set({}, "{a..b}.c", "d")); | ||
//=> { '{a..b}': { c: 'd' } } | ||
``` | ||
### Running the benchmarks | ||
Clone this library into a local directory: | ||
```sh | ||
$ git clone https://github.com/jonschlinkert/set-value.git | ||
``` | ||
Then install devDependencies and run benchmarks: | ||
```sh | ||
$ npm install && node benchmark | ||
``` | ||
## Comparisons to other libs, or _"the list of shame"_ | ||
These are just a few of the duplicate libraries on NPM. | ||
* [bury](https://github.com/kalmbach/bury) fails all of the tests. I even wrapped it to have it return the object instead of the value, but with all of that work it still fails the vast majority of tests. | ||
* [deep-get-set](https://github.com/acstll/deep-get-set) fails 22 of 26 unit tests. | ||
* [deep-object](https://github.com/ayushgp/deep-object) fails 25 of 26 unit tests, completely butchered given objects. | ||
* [deep-property](https://github.com/mikattack/node-deep-property) fails 17 of 26 unit tests. | ||
* [deep-set](https://github.com/klaemo/deep-set) fails 13 of 26 unit tests. | ||
* [deephas](https://github.com/sharpred/deepHas) fails 17 of 26 unit tests. | ||
* [dot-prop](https://github.com/sindresorhus/dot-prop) fails 9 of 26 unit tests. | ||
* [dot2val](https://github.com/yangg/dot2val) fails 17 of 26 unit tests. | ||
* [es5-dot-prop](https://github.com/sindresorhus/dot-prop) fails 15 of 26 unit tests. | ||
* [getsetdeep](https://github.com/bevry/getsetdeep) fails all unit tests due to `this` being used improperly in the methods. I was able to patch it by binding the (plain) object to the methods, but it still fails 17 of 26 unit tests. | ||
* [lodash.set](https://lodash.com/) fails 11 of 26 unit tests. | ||
* [object-path-set](https://github.com/skratchdot/object-path-set) fails 12 of 26 unit tests. | ||
* [object-path](https://github.com/mariocasciaro/object-path) fails 16 of 26 unit tests. | ||
* [object-set](https://github.com/gearcase/object-set) fails 13 of 26 unit tests. | ||
* [set-nested-prop](https://github.com/tiaanduplessis/set-nested-prop) fails 24 of 26 unit tests. | ||
* [setvalue](https://github.com/blakeembrey/setvalue) (this library is almost identical to a previous version of this library) | ||
* Many dozens of others | ||
**Others that do the same thing, but use a completely different API** | ||
* [deep-set-in](https://github.com/KulikovskyIgor/deep-set-in) | ||
* [set-deep](https://github.com/radubrehar/set-deep) | ||
* [set-deep-prop](https://github.com/mmckelvy/set-deep-prop) | ||
* [bury](https://github.com/kalmbach/bury) | ||
* Many dozens of others | ||
## History | ||
### v3.0.0 | ||
* Added support for a custom `split` function to be passed on the options. | ||
* Removed support for splitting on brackets, since a [custom function](https://github.com/jonschlinkert/split-string) can be passed to do this now. | ||
### v2.0.0 | ||
@@ -97,27 +169,23 @@ | ||
### Related projects | ||
<details> | ||
<summary><strong>Contributing</strong></summary> | ||
* [assign-value](https://www.npmjs.com/package/assign-value): Assign a value or extend a deeply nested property of an object using object path… [more](https://github.com/jonschlinkert/assign-value) | [homepage](https://github.com/jonschlinkert/assign-value "Assign a value or extend a deeply nested property of an object using object path notation.") | ||
* [get-value](https://www.npmjs.com/package/get-value): Use property paths (`a.b.c`) to get a nested value from an object. | [homepage](https://github.com/jonschlinkert/get-value "Use property paths (`a.b.c`) to get a nested value from an object.") | ||
* [has-value](https://www.npmjs.com/package/has-value): Returns true if a value exists, false if empty. Works with deeply nested values using… [more](https://github.com/jonschlinkert/has-value) | [homepage](https://github.com/jonschlinkert/has-value "Returns true if a value exists, false if empty. Works with deeply nested values using object paths.") | ||
* [merge-value](https://www.npmjs.com/package/merge-value): Similar to assign-value but deeply merges object values or nested values using object path/dot notation. | [homepage](https://github.com/jonschlinkert/merge-value "Similar to assign-value but deeply merges object values or nested values using object path/dot notation.") | ||
* [omit-value](https://www.npmjs.com/package/omit-value): Omit properties from an object or deeply nested property of an object using object path… [more](https://github.com/jonschlinkert/omit-value) | [homepage](https://github.com/jonschlinkert/omit-value "Omit properties from an object or deeply nested property of an object using object path notation.") | ||
* [set-value](https://www.npmjs.com/package/set-value): Create nested values and any intermediaries using dot notation (`'a.b.c'`) paths. | [homepage](https://github.com/jonschlinkert/set-value "Create nested values and any intermediaries using dot notation (`'a.b.c'`) paths.") | ||
* [union-value](https://www.npmjs.com/package/union-value): Set an array of unique values as the property of an object. Supports setting deeply… [more](https://github.com/jonschlinkert/union-value) | [homepage](https://github.com/jonschlinkert/union-value "Set an array of unique values as the property of an object. Supports setting deeply nested properties using using object-paths/dot notation.") | ||
* [unset-value](https://www.npmjs.com/package/unset-value): Delete nested properties from an object using dot notation. | [homepage](https://github.com/jonschlinkert/unset-value "Delete nested properties from an object using dot notation.") | ||
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new). | ||
### Contributing | ||
</details> | ||
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new). | ||
<details> | ||
<summary><strong>Running Tests</strong></summary> | ||
### Contributors | ||
Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command: | ||
| **Commits** | **Contributor** | | ||
| --- | --- | | ||
| 59 | [jonschlinkert](https://github.com/jonschlinkert) | | ||
| 1 | [vadimdemedes](https://github.com/vadimdemedes) | | ||
| 1 | [wtgtybhertgeghgtwtg](https://github.com/wtgtybhertgeghgtwtg) | | ||
```sh | ||
$ npm install && npm test | ||
``` | ||
### Building docs | ||
</details> | ||
<details> | ||
<summary><strong>Building docs</strong></summary> | ||
_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_ | ||
@@ -131,10 +199,25 @@ | ||
### Running tests | ||
</details> | ||
Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command: | ||
### Related projects | ||
```sh | ||
$ npm install && npm test | ||
``` | ||
You might also be interested in these projects: | ||
* [assign-value](https://www.npmjs.com/package/assign-value): Assign a value or extend a deeply nested property of an object using object path… [more](https://github.com/jonschlinkert/assign-value) | [homepage](https://github.com/jonschlinkert/assign-value "Assign a value or extend a deeply nested property of an object using object path notation.") | ||
* [get-value](https://www.npmjs.com/package/get-value): Use property paths like 'a.b.c' to get a nested value from an object. Even works… [more](https://github.com/jonschlinkert/get-value) | [homepage](https://github.com/jonschlinkert/get-value "Use property paths like 'a.b.c' to get a nested value from an object. Even works when keys have dots in them (no other dot-prop library can do this!).") | ||
* [has-value](https://www.npmjs.com/package/has-value): Returns true if a value exists, false if empty. Works with deeply nested values using… [more](https://github.com/jonschlinkert/has-value) | [homepage](https://github.com/jonschlinkert/has-value "Returns true if a value exists, false if empty. Works with deeply nested values using object paths.") | ||
* [merge-value](https://www.npmjs.com/package/merge-value): Similar to assign-value but deeply merges object values or nested values using object path/dot notation. | [homepage](https://github.com/jonschlinkert/merge-value "Similar to assign-value but deeply merges object values or nested values using object path/dot notation.") | ||
* [omit-value](https://www.npmjs.com/package/omit-value): Omit properties from an object or deeply nested property of an object using object path… [more](https://github.com/jonschlinkert/omit-value) | [homepage](https://github.com/jonschlinkert/omit-value "Omit properties from an object or deeply nested property of an object using object path notation.") | ||
* [set-value](https://www.npmjs.com/package/set-value): Create nested values and any intermediaries using dot notation (`'a.b.c'`) paths. | [homepage](https://github.com/jonschlinkert/set-value "Create nested values and any intermediaries using dot notation (`'a.b.c'`) paths.") | ||
* [union-value](https://www.npmjs.com/package/union-value): Set an array of unique values as the property of an object. Supports setting deeply… [more](https://github.com/jonschlinkert/union-value) | [homepage](https://github.com/jonschlinkert/union-value "Set an array of unique values as the property of an object. Supports setting deeply nested properties using using object-paths/dot notation.") | ||
* [unset-value](https://www.npmjs.com/package/unset-value): Delete nested properties from an object using dot notation. | [homepage](https://github.com/jonschlinkert/unset-value "Delete nested properties from an object using dot notation.") | ||
### Contributors | ||
| **Commits** | **Contributor** | | ||
| --- | --- | | ||
| 64 | [jonschlinkert](https://github.com/jonschlinkert) | | ||
| 1 | [vadimdemedes](https://github.com/vadimdemedes) | | ||
| 1 | [wtgtybhertgeghgtwtg](https://github.com/wtgtybhertgeghgtwtg) | | ||
### Author | ||
@@ -144,8 +227,9 @@ | ||
* [github/jonschlinkert](https://github.com/jonschlinkert) | ||
* [twitter/jonschlinkert](https://twitter.com/jonschlinkert) | ||
* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert) | ||
* [GitHub Profile](https://github.com/jonschlinkert) | ||
* [Twitter Profile](https://twitter.com/jonschlinkert) | ||
### License | ||
Copyright © 2017, [Jon Schlinkert](https://github.com/jonschlinkert). | ||
Copyright © 2018, [Jon Schlinkert](https://github.com/jonschlinkert). | ||
Released under the [MIT License](LICENSE). | ||
@@ -155,2 +239,2 @@ | ||
_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on June 21, 2017._ | ||
_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on March 05, 2018._ |
Sorry, the diff of this file is not supported yet
17299
1
96
234
16
- Removedextend-shallow@^2.0.1
- Removedis-extendable@^0.1.1
- Removedsplit-string@^3.0.1
- Removedassign-symbols@1.0.0(transitive)
- Removedextend-shallow@2.0.13.0.2(transitive)
- Removedis-extendable@0.1.11.0.1(transitive)
- Removedsplit-string@3.1.0(transitive)
Updatedis-plain-object@^2.0.4