dot-object 2.1.0 → 2.1.4

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # ChangeLog
2
2
 
3
+ ## 2020-09-10 Version 2.1.4
4
+ * [[`94b9eb8a2d`](https://github.com/rhalff/dot-object/commit/94b9eb8a2d)] - Fix parsing of array paths for non standard separators (Fixed by boidolr #58)
5
+
6
+ ## 2020-02-16 Version 2.1.3
7
+ * fix possible pollution of prototype for paths containing __proto__
8
+
9
+ ## 2019-11-02 Version 2.1.1
10
+ * fix undefined key with root level array.
11
+
12
+ ## 2019-11-02 Version 2.1.1
13
+ * Wrong array conversion when brackets are used (Reported by vladshcherbin #27)
14
+
3
15
  ## 2019-11-02 Version 2.1.0
4
16
  * fix delete function not being wrapped. (Reported by murphyke #40)
5
17
 
package/README.md CHANGED
@@ -359,6 +359,33 @@ Result:
359
359
  }
360
360
  ```
361
361
 
362
+ ### Keep array
363
+
364
+ Set keepArray to true.
365
+
366
+ ```javascript
367
+ var dot = require('dot-object');
368
+
369
+ var obj = {
370
+ id: 'my-id',
371
+ other: [1, 2, 3],
372
+ some: { array: ['A', 'B'] }
373
+ };
374
+
375
+ dot.keepArray = true;
376
+ var tgt = dot.dot(obj);
377
+
378
+ console.log(tgt);
379
+ ```
380
+ Result:
381
+ ```json
382
+ {
383
+ "id": "my-id",
384
+ "other": [1, 2, 3],
385
+ "some.array": ["A", "B"]
386
+ }
387
+ ```
388
+
362
389
  ## Using a different separator
363
390
 
364
391
  If you do not like dot notation, you are free to specify a different separator.
package/bower.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dot-object",
3
- "version": "2.1.0",
3
+ "version": "2.1.4",
4
4
  "description": "dot-object makes it possible to transform and read (JSON) objects using dot notation.",
5
5
  "main": "dist/dot-object.js",
6
6
  "authors": [
@@ -46,11 +46,25 @@
46
46
  return Object.keys(val).length === 0
47
47
  }
48
48
 
49
+ var blacklist = ['__proto__', 'prototype', 'constructor']
50
+ var blacklistFilter = function(part) {
51
+ return blacklist.indexOf(part) === -1
52
+ }
53
+
49
54
  function parsePath(path, sep) {
50
55
  if (path.indexOf('[') >= 0) {
51
- path = path.replace(/\[/g, '.').replace(/]/g, '')
56
+ path = path.replace(/\[/g, sep).replace(/]/g, '')
57
+ }
58
+
59
+ var parts = path.split(sep)
60
+
61
+ var check = parts.filter(blacklistFilter)
62
+
63
+ if (check.length !== parts.length) {
64
+ throw Error('Refusing to update blacklisted property ' + path)
52
65
  }
53
- return path.split(sep)
66
+
67
+ return parts
54
68
  }
55
69
 
56
70
  var hasOwnProperty = Object.prototype.hasOwnProperty
@@ -85,8 +99,7 @@
85
99
  var k = a.shift()
86
100
 
87
101
  if (a.length > 0) {
88
- obj[k] = obj[k] ||
89
- (this.useArray && isIndex(a[0]) ? [] : {})
102
+ obj[k] = obj[k] || (this.useArray && isIndex(a[0]) ? [] : {})
90
103
 
91
104
  if (!isArrayOrObject(obj[k])) {
92
105
  if (this.override) {
@@ -104,8 +117,7 @@
104
117
 
105
118
  this._fill(a, obj[k], v, mod)
106
119
  } else {
107
- if (!this.override &&
108
- isArrayOrObject(obj[k]) && !isEmptyObject(obj[k])) {
120
+ if (!this.override && isArrayOrObject(obj[k]) && !isEmptyObject(obj[k])) {
109
121
  if (!(isArrayOrObject(v) && isEmptyObject(v))) {
110
122
  throw new Error("Trying to redefine non-empty obj['" + k + "']")
111
123
  }
@@ -165,8 +177,10 @@
165
177
  * @param {Function|Array} mod optional modifier
166
178
  */
167
179
  DotObject.prototype.str = function(path, v, obj, mod) {
180
+ var ok = parsePath(path, this.separator).join(this.separator)
181
+
168
182
  if (path.indexOf(this.separator) !== -1) {
169
- this._fill(path.split(this.separator), obj, v, mod)
183
+ this._fill(ok.split(this.separator), obj, v, mod)
170
184
  } else {
171
185
  obj[path] = _process(v, mod)
172
186
  }
@@ -195,7 +209,7 @@
195
209
  for (i = 0; i < keys.length; i++) {
196
210
  key = parseKey(keys[i], obj)
197
211
  if (obj && typeof obj === 'object' && key in obj) {
198
- if (i === (keys.length - 1)) {
212
+ if (i === keys.length - 1) {
199
213
  if (remove) {
200
214
  val = obj[key]
201
215
  if (reindexArray && Array.isArray(obj)) {
@@ -340,13 +354,21 @@
340
354
  * @param {Function|Array} mods
341
355
  * @param {Boolean} merge
342
356
  */
343
- DotObject.prototype.transfer = function(source, target, obj1, obj2, mods, merge) {
357
+ DotObject.prototype.transfer = function(
358
+ source,
359
+ target,
360
+ obj1,
361
+ obj2,
362
+ mods,
363
+ merge
364
+ ) {
344
365
  if (typeof mods === 'function' || Array.isArray(mods)) {
345
- this.set(target,
346
- _process(
347
- this.pick(source, obj1, true),
348
- mods
349
- ), obj2, merge)
366
+ this.set(
367
+ target,
368
+ _process(this.pick(source, obj1, true), mods),
369
+ obj2,
370
+ merge
371
+ )
350
372
  } else {
351
373
  merge = mods
352
374
  this.set(target, this.pick(source, obj1, true), obj2, merge)
@@ -371,16 +393,16 @@
371
393
  */
372
394
  DotObject.prototype.copy = function(source, target, obj1, obj2, mods, merge) {
373
395
  if (typeof mods === 'function' || Array.isArray(mods)) {
374
- this.set(target,
396
+ this.set(
397
+ target,
375
398
  _process(
376
399
  // clone what is picked
377
- JSON.parse(
378
- JSON.stringify(
379
- this.pick(source, obj1, false)
380
- )
381
- ),
400
+ JSON.parse(JSON.stringify(this.pick(source, obj1, false))),
382
401
  mods
383
- ), obj2, merge)
402
+ ),
403
+ obj2,
404
+ merge
405
+ )
384
406
  } else {
385
407
  merge = mods
386
408
  this.set(target, this.pick(source, obj1, false), obj2, merge)
@@ -412,7 +434,7 @@
412
434
 
413
435
  for (i = 0; i < keys.length; i++) {
414
436
  key = keys[i]
415
- if (i === (keys.length - 1)) {
437
+ if (i === keys.length - 1) {
416
438
  if (merge && isObject(val) && isObject(obj[key])) {
417
439
  for (k in val) {
418
440
  if (hasOwnProperty.call(val, k)) {
@@ -470,9 +492,11 @@
470
492
  DotObject.prototype.transform = function(recipe, obj, tgt) {
471
493
  obj = obj || {}
472
494
  tgt = tgt || {}
473
- Object.keys(recipe).forEach(function(key) {
474
- this.set(recipe[key], this.pick(key, obj), tgt)
475
- }.bind(this))
495
+ Object.keys(recipe).forEach(
496
+ function(key) {
497
+ this.set(recipe[key], this.pick(key, obj), tgt)
498
+ }.bind(this)
499
+ )
476
500
  return tgt
477
501
  }
478
502
 
@@ -498,30 +522,33 @@
498
522
  path = path || []
499
523
  var isArray = Array.isArray(obj)
500
524
 
501
- Object.keys(obj).forEach(function(key) {
502
- var index = isArray && this.useBrackets ? '[' + key + ']' : key
503
- if (
504
- (
525
+ Object.keys(obj).forEach(
526
+ function(key) {
527
+ var index = isArray && this.useBrackets ? '[' + key + ']' : key
528
+ if (
505
529
  isArrayOrObject(obj[key]) &&
506
- (
507
- (isObject(obj[key]) && !isEmptyObject(obj[key])) ||
508
- (Array.isArray(obj[key]) && (!this.keepArray && (obj[key].length !== 0)))
509
- )
510
- )
511
- ) {
512
- if (isArray && this.useBrackets) {
513
- return this.dot(obj[key], tgt, path.slice(0, -1).concat(path[path.length - 1] + index))
514
- } else {
515
- return this.dot(obj[key], tgt, path.concat(index))
516
- }
517
- } else {
518
- if (isArray && this.useBrackets) {
519
- tgt[path.join(this.separator).concat('[' + key + ']')] = obj[key]
530
+ ((isObject(obj[key]) && !isEmptyObject(obj[key])) ||
531
+ (Array.isArray(obj[key]) && !this.keepArray && obj[key].length !== 0))
532
+ ) {
533
+ if (isArray && this.useBrackets) {
534
+ var previousKey = path[path.length - 1] || ''
535
+ return this.dot(
536
+ obj[key],
537
+ tgt,
538
+ path.slice(0, -1).concat(previousKey + index)
539
+ )
540
+ } else {
541
+ return this.dot(obj[key], tgt, path.concat(index))
542
+ }
520
543
  } else {
521
- tgt[path.concat(index).join(this.separator)] = obj[key]
544
+ if (isArray && this.useBrackets) {
545
+ tgt[path.join(this.separator).concat('[' + key + ']')] = obj[key]
546
+ } else {
547
+ tgt[path.concat(index).join(this.separator)] = obj[key]
548
+ }
522
549
  }
523
- }
524
- }.bind(this))
550
+ }.bind(this)
551
+ )
525
552
  return tgt
526
553
  }
527
554
 
@@ -535,9 +562,7 @@
535
562
  DotObject.set = wrap('set')
536
563
  DotObject.delete = wrap('delete')
537
564
  DotObject.del = DotObject.remove = wrap('remove')
538
- DotObject.dot = wrap('dot')
539
-
540
- ;
565
+ DotObject.dot = wrap('dot');
541
566
  ['override', 'overwrite'].forEach(function(prop) {
542
567
  Object.defineProperty(DotObject, prop, {
543
568
  get: function() {
@@ -547,9 +572,7 @@
547
572
  dotDefault.override = !!val
548
573
  }
549
574
  })
550
- })
551
-
552
- ;
575
+ });
553
576
  ['useArray', 'keepArray', 'useBrackets'].forEach(function(prop) {
554
577
  Object.defineProperty(DotObject, prop, {
555
578
  get: function() {
@@ -1 +1 @@
1
- !function(t){"use strict";function s(t,r){var e,i;if("function"==typeof r)void 0!==(i=r(t))&&(t=i);else if(Array.isArray(r))for(e=0;e<r.length;e++)void 0!==(i=r[e](t))&&(t=i);return t}function f(t){return"[object Object]"===Object.prototype.toString.call(t)}function c(t){return Object(t)===t}function a(t){return 0===Object.keys(t).length}function u(t,r){return 0<=t.indexOf("[")&&(t=t.replace(/\[/g,".").replace(/]/g,"")),t.split(r)}var p=Object.prototype.hasOwnProperty;function n(t,r,e,i){if(!(this instanceof n))return new n(t,r,e,i);void 0===r&&(r=!1),void 0===e&&(e=!0),void 0===i&&(i=!0),this.separator=t||".",this.override=r,this.useArray=e,this.useBrackets=i,this.keepArray=!1,this.cleanup=[]}var e=new n(".",!1,!0,!0);function r(t){return function(){return e[t].apply(e,arguments)}}n.prototype._fill=function(t,r,e,i){var n=t.shift();if(0<t.length){if(r[n]=r[n]||(this.useArray&&function(t){return/^\d+$/.test(t)}(t[0])?[]:{}),!c(r[n])){if(!this.override){if(!c(e)||!a(e))throw new Error("Trying to redefine `"+n+"` which is a "+typeof r[n]);return}r[n]={}}this._fill(t,r[n],e,i)}else{if(!this.override&&c(r[n])&&!a(r[n])){if(!c(e)||!a(e))throw new Error("Trying to redefine non-empty obj['"+n+"']");return}r[n]=s(e,i)}},n.prototype.object=function(i,n){var o=this;return Object.keys(i).forEach(function(t){var r=void 0===n?null:n[t],e=u(t,o.separator).join(o.separator);-1!==e.indexOf(o.separator)?(o._fill(e.split(o.separator),i,i[t],r),delete i[t]):i[t]=s(i[t],r)}),i},n.prototype.str=function(t,r,e,i){return-1!==t.indexOf(this.separator)?this._fill(t.split(this.separator),e,r,i):e[t]=s(r,i),e},n.prototype.pick=function(t,r,e,i){var n,o,s,c,a,f,p;for(o=u(t,this.separator),n=0;n<o.length;n++){if(f=o[n],p=r,c="-"===f[0]&&Array.isArray(p)&&/^-\d+$/.test(f)?p.length+parseInt(f,10):f,!(r&&"object"==typeof r&&c in r))return;if(n===o.length-1)return e?(s=r[c],i&&Array.isArray(r)?r.splice(c,1):delete r[c],Array.isArray(r)&&(a=o.slice(0,-1).join("."),-1===this.cleanup.indexOf(a)&&this.cleanup.push(a)),s):r[c];r=r[c]}return e&&Array.isArray(r)&&(r=r.filter(function(t){return void 0!==t})),r},n.prototype.delete=function(t,r){return this.remove(t,r,!0)},n.prototype.remove=function(t,r,e){var i;if(this.cleanup=[],Array.isArray(t)){for(i=0;i<t.length;i++)this.pick(t[i],r,!0,e);return e||this._cleanup(r),r}return this.pick(t,r,!0,e)},n.prototype._cleanup=function(t){var r,e,i,n;if(this.cleanup.length){for(e=0;e<this.cleanup.length;e++)r=(r=(n=(i=this.cleanup[e].split(".")).splice(0,-1).join("."))?this.pick(n,t):t)[i[0]].filter(function(t){return void 0!==t}),this.set(this.cleanup[e],r,t);this.cleanup=[]}},n.prototype.del=n.prototype.remove,n.prototype.move=function(t,r,e,i,n){return"function"==typeof i||Array.isArray(i)?this.set(r,s(this.pick(t,e,!0),i),e,n):(n=i,this.set(r,this.pick(t,e,!0),e,n)),e},n.prototype.transfer=function(t,r,e,i,n,o){return"function"==typeof n||Array.isArray(n)?this.set(r,s(this.pick(t,e,!0),n),i,o):(o=n,this.set(r,this.pick(t,e,!0),i,o)),i},n.prototype.copy=function(t,r,e,i,n,o){return"function"==typeof n||Array.isArray(n)?this.set(r,s(JSON.parse(JSON.stringify(this.pick(t,e,!1))),n),i,o):(o=n,this.set(r,this.pick(t,e,!1),i,o)),i},n.prototype.set=function(t,r,e,i){var n,o,s,c;if(void 0===r)return e;for(s=u(t,this.separator),n=0;n<s.length;n++){if(c=s[n],n===s.length-1)if(i&&f(r)&&f(e[c]))for(o in r)p.call(r,o)&&(e[c][o]=r[o]);else if(i&&Array.isArray(e[c])&&Array.isArray(r))for(var a=0;a<r.length;a++)e[s[n]].push(r[a]);else e[c]=r;else p.call(e,c)&&(f(e[c])||Array.isArray(e[c]))||(/^\d+$/.test(s[n+1])?e[c]=[]:e[c]={});e=e[c]}return e},n.prototype.transform=function(r,e,i){return e=e||{},i=i||{},Object.keys(r).forEach(function(t){this.set(r[t],this.pick(t,e),i)}.bind(this)),i},n.prototype.dot=function(e,i,n){i=i||{},n=n||[];var o=Array.isArray(e);return Object.keys(e).forEach(function(t){var r=o&&this.useBrackets?"["+t+"]":t;if(c(e[t])&&(f(e[t])&&!a(e[t])||Array.isArray(e[t])&&!this.keepArray&&0!==e[t].length))return o&&this.useBrackets?this.dot(e[t],i,n.slice(0,-1).concat(n[n.length-1]+r)):this.dot(e[t],i,n.concat(r));o&&this.useBrackets?i[n.join(this.separator).concat("["+t+"]")]=e[t]:i[n.concat(r).join(this.separator)]=e[t]}.bind(this)),i},n.pick=r("pick"),n.move=r("move"),n.transfer=r("transfer"),n.transform=r("transform"),n.copy=r("copy"),n.object=r("object"),n.str=r("str"),n.set=r("set"),n.delete=r("delete"),n.del=n.remove=r("remove"),n.dot=r("dot"),["override","overwrite"].forEach(function(t){Object.defineProperty(n,t,{get:function(){return e.override},set:function(t){e.override=!!t}})}),["useArray","keepArray","useBrackets"].forEach(function(r){Object.defineProperty(n,r,{get:function(){return e[r]},set:function(t){e[r]=t}})}),n._process=s,"function"==typeof define&&define.amd?define(function(){return n}):"undefined"!=typeof module&&module.exports?module.exports=n:t.DotObject=n}(this);
1
+ !function(t){"use strict";function s(t,r){var e,i;if("function"==typeof r)void 0!==(i=r(t))&&(t=i);else if(Array.isArray(r))for(e=0;e<r.length;e++)void 0!==(i=r[e](t))&&(t=i);return t}function p(t){return"[object Object]"===Object.prototype.toString.call(t)}function a(t){return Object(t)===t}function c(t){return 0===Object.keys(t).length}function i(t){return-1===r.indexOf(t)}var r=["__proto__","prototype","constructor"];function u(t,r){0<=t.indexOf("[")&&(t=t.replace(/\[/g,r).replace(/]/g,""));var e=t.split(r);if(e.filter(i).length!==e.length)throw Error("Refusing to update blacklisted property "+t);return e}var f=Object.prototype.hasOwnProperty;function n(t,r,e,i){if(!(this instanceof n))return new n(t,r,e,i);void 0===r&&(r=!1),void 0===e&&(e=!0),void 0===i&&(i=!0),this.separator=t||".",this.override=r,this.useArray=e,this.useBrackets=i,this.keepArray=!1,this.cleanup=[]}var e=new n(".",!1,!0,!0);function o(t){return function(){return e[t].apply(e,arguments)}}n.prototype._fill=function(t,r,e,i){var n=t.shift();if(0<t.length){if(r[n]=r[n]||(this.useArray&&function(t){return/^\d+$/.test(t)}(t[0])?[]:{}),!a(r[n])){if(!this.override){if(!a(e)||!c(e))throw new Error("Trying to redefine `"+n+"` which is a "+typeof r[n]);return}r[n]={}}this._fill(t,r[n],e,i)}else{if(!this.override&&a(r[n])&&!c(r[n])){if(!a(e)||!c(e))throw new Error("Trying to redefine non-empty obj['"+n+"']");return}r[n]=s(e,i)}},n.prototype.object=function(i,n){var o=this;return Object.keys(i).forEach(function(t){var r=void 0===n?null:n[t],e=u(t,o.separator).join(o.separator);-1!==e.indexOf(o.separator)?(o._fill(e.split(o.separator),i,i[t],r),delete i[t]):i[t]=s(i[t],r)}),i},n.prototype.str=function(t,r,e,i){var n=u(t,this.separator).join(this.separator);return-1!==t.indexOf(this.separator)?this._fill(n.split(this.separator),e,r,i):e[t]=s(r,i),e},n.prototype.pick=function(t,r,e,i){var n,o,s,a,c,p,f;for(o=u(t,this.separator),n=0;n<o.length;n++){if(p=o[n],f=r,a="-"===p[0]&&Array.isArray(f)&&/^-\d+$/.test(p)?f.length+parseInt(p,10):p,!(r&&"object"==typeof r&&a in r))return;if(n===o.length-1)return e?(s=r[a],i&&Array.isArray(r)?r.splice(a,1):delete r[a],Array.isArray(r)&&(c=o.slice(0,-1).join("."),-1===this.cleanup.indexOf(c)&&this.cleanup.push(c)),s):r[a];r=r[a]}return e&&Array.isArray(r)&&(r=r.filter(function(t){return void 0!==t})),r},n.prototype.delete=function(t,r){return this.remove(t,r,!0)},n.prototype.remove=function(t,r,e){var i;if(this.cleanup=[],Array.isArray(t)){for(i=0;i<t.length;i++)this.pick(t[i],r,!0,e);return e||this._cleanup(r),r}return this.pick(t,r,!0,e)},n.prototype._cleanup=function(t){var r,e,i,n;if(this.cleanup.length){for(e=0;e<this.cleanup.length;e++)r=(r=(n=(i=this.cleanup[e].split(".")).splice(0,-1).join("."))?this.pick(n,t):t)[i[0]].filter(function(t){return void 0!==t}),this.set(this.cleanup[e],r,t);this.cleanup=[]}},n.prototype.del=n.prototype.remove,n.prototype.move=function(t,r,e,i,n){return"function"==typeof i||Array.isArray(i)?this.set(r,s(this.pick(t,e,!0),i),e,n):(n=i,this.set(r,this.pick(t,e,!0),e,n)),e},n.prototype.transfer=function(t,r,e,i,n,o){return"function"==typeof n||Array.isArray(n)?this.set(r,s(this.pick(t,e,!0),n),i,o):(o=n,this.set(r,this.pick(t,e,!0),i,o)),i},n.prototype.copy=function(t,r,e,i,n,o){return"function"==typeof n||Array.isArray(n)?this.set(r,s(JSON.parse(JSON.stringify(this.pick(t,e,!1))),n),i,o):(o=n,this.set(r,this.pick(t,e,!1),i,o)),i},n.prototype.set=function(t,r,e,i){var n,o,s,a;if(void 0===r)return e;for(s=u(t,this.separator),n=0;n<s.length;n++){if(a=s[n],n===s.length-1)if(i&&p(r)&&p(e[a]))for(o in r)f.call(r,o)&&(e[a][o]=r[o]);else if(i&&Array.isArray(e[a])&&Array.isArray(r))for(var c=0;c<r.length;c++)e[s[n]].push(r[c]);else e[a]=r;else f.call(e,a)&&(p(e[a])||Array.isArray(e[a]))||(/^\d+$/.test(s[n+1])?e[a]=[]:e[a]={});e=e[a]}return e},n.prototype.transform=function(r,e,i){return e=e||{},i=i||{},Object.keys(r).forEach(function(t){this.set(r[t],this.pick(t,e),i)}.bind(this)),i},n.prototype.dot=function(i,n,o){n=n||{},o=o||[];var s=Array.isArray(i);return Object.keys(i).forEach(function(t){var r=s&&this.useBrackets?"["+t+"]":t;if(a(i[t])&&(p(i[t])&&!c(i[t])||Array.isArray(i[t])&&!this.keepArray&&0!==i[t].length)){if(s&&this.useBrackets){var e=o[o.length-1]||"";return this.dot(i[t],n,o.slice(0,-1).concat(e+r))}return this.dot(i[t],n,o.concat(r))}s&&this.useBrackets?n[o.join(this.separator).concat("["+t+"]")]=i[t]:n[o.concat(r).join(this.separator)]=i[t]}.bind(this)),n},n.pick=o("pick"),n.move=o("move"),n.transfer=o("transfer"),n.transform=o("transform"),n.copy=o("copy"),n.object=o("object"),n.str=o("str"),n.set=o("set"),n.delete=o("delete"),n.del=n.remove=o("remove"),n.dot=o("dot"),["override","overwrite"].forEach(function(t){Object.defineProperty(n,t,{get:function(){return e.override},set:function(t){e.override=!!t}})}),["useArray","keepArray","useBrackets"].forEach(function(r){Object.defineProperty(n,r,{get:function(){return e[r]},set:function(t){e[r]=t}})}),n._process=s,"function"==typeof define&&define.amd?define(function(){return n}):"undefined"!=typeof module&&module.exports?module.exports=n:t.DotObject=n}(this);
package/index.js CHANGED
@@ -45,11 +45,23 @@ function isEmptyObject (val) {
45
45
  return Object.keys(val).length === 0
46
46
  }
47
47
 
48
+ var blacklist = ['__proto__', 'prototype', 'constructor']
49
+ var blacklistFilter = function (part) { return blacklist.indexOf(part) === -1 }
50
+
48
51
  function parsePath (path, sep) {
49
52
  if (path.indexOf('[') >= 0) {
50
- path = path.replace(/\[/g, '.').replace(/]/g, '')
53
+ path = path.replace(/\[/g, sep).replace(/]/g, '')
54
+ }
55
+
56
+ var parts = path.split(sep)
57
+
58
+ var check = parts.filter(blacklistFilter)
59
+
60
+ if (check.length !== parts.length) {
61
+ throw Error('Refusing to update blacklisted property ' + path)
51
62
  }
52
- return path.split(sep)
63
+
64
+ return parts
53
65
  }
54
66
 
55
67
  var hasOwnProperty = Object.prototype.hasOwnProperty
@@ -83,8 +95,7 @@ DotObject.prototype._fill = function (a, obj, v, mod) {
83
95
  var k = a.shift()
84
96
 
85
97
  if (a.length > 0) {
86
- obj[k] = obj[k] ||
87
- (this.useArray && isIndex(a[0]) ? [] : {})
98
+ obj[k] = obj[k] || (this.useArray && isIndex(a[0]) ? [] : {})
88
99
 
89
100
  if (!isArrayOrObject(obj[k])) {
90
101
  if (this.override) {
@@ -102,8 +113,7 @@ DotObject.prototype._fill = function (a, obj, v, mod) {
102
113
 
103
114
  this._fill(a, obj[k], v, mod)
104
115
  } else {
105
- if (!this.override &&
106
- isArrayOrObject(obj[k]) && !isEmptyObject(obj[k])) {
116
+ if (!this.override && isArrayOrObject(obj[k]) && !isEmptyObject(obj[k])) {
107
117
  if (!(isArrayOrObject(v) && isEmptyObject(v))) {
108
118
  throw new Error("Trying to redefine non-empty obj['" + k + "']")
109
119
  }
@@ -163,8 +173,10 @@ DotObject.prototype.object = function (obj, mods) {
163
173
  * @param {Function|Array} mod optional modifier
164
174
  */
165
175
  DotObject.prototype.str = function (path, v, obj, mod) {
176
+ var ok = parsePath(path, this.separator).join(this.separator)
177
+
166
178
  if (path.indexOf(this.separator) !== -1) {
167
- this._fill(path.split(this.separator), obj, v, mod)
179
+ this._fill(ok.split(this.separator), obj, v, mod)
168
180
  } else {
169
181
  obj[path] = _process(v, mod)
170
182
  }
@@ -193,7 +205,7 @@ DotObject.prototype.pick = function (path, obj, remove, reindexArray) {
193
205
  for (i = 0; i < keys.length; i++) {
194
206
  key = parseKey(keys[i], obj)
195
207
  if (obj && typeof obj === 'object' && key in obj) {
196
- if (i === (keys.length - 1)) {
208
+ if (i === keys.length - 1) {
197
209
  if (remove) {
198
210
  val = obj[key]
199
211
  if (reindexArray && Array.isArray(obj)) {
@@ -219,7 +231,9 @@ DotObject.prototype.pick = function (path, obj, remove, reindexArray) {
219
231
  }
220
232
  }
221
233
  if (remove && Array.isArray(obj)) {
222
- obj = obj.filter(function (n) { return n !== undefined })
234
+ obj = obj.filter(function (n) {
235
+ return n !== undefined
236
+ })
223
237
  }
224
238
  return obj
225
239
  }
@@ -277,7 +291,9 @@ DotObject.prototype._cleanup = function (obj) {
277
291
  keys = this.cleanup[i].split('.')
278
292
  root = keys.splice(0, -1).join('.')
279
293
  ret = root ? this.pick(root, obj) : obj
280
- ret = ret[keys[0]].filter(function (v) { return v !== undefined })
294
+ ret = ret[keys[0]].filter(function (v) {
295
+ return v !== undefined
296
+ })
281
297
  this.set(this.cleanup[i], ret, obj)
282
298
  }
283
299
  this.cleanup = []
@@ -334,13 +350,21 @@ DotObject.prototype.move = function (source, target, obj, mods, merge) {
334
350
  * @param {Function|Array} mods
335
351
  * @param {Boolean} merge
336
352
  */
337
- DotObject.prototype.transfer = function (source, target, obj1, obj2, mods, merge) {
353
+ DotObject.prototype.transfer = function (
354
+ source,
355
+ target,
356
+ obj1,
357
+ obj2,
358
+ mods,
359
+ merge
360
+ ) {
338
361
  if (typeof mods === 'function' || Array.isArray(mods)) {
339
- this.set(target,
340
- _process(
341
- this.pick(source, obj1, true),
342
- mods
343
- ), obj2, merge)
362
+ this.set(
363
+ target,
364
+ _process(this.pick(source, obj1, true), mods),
365
+ obj2,
366
+ merge
367
+ )
344
368
  } else {
345
369
  merge = mods
346
370
  this.set(target, this.pick(source, obj1, true), obj2, merge)
@@ -365,16 +389,16 @@ DotObject.prototype.transfer = function (source, target, obj1, obj2, mods, merge
365
389
  */
366
390
  DotObject.prototype.copy = function (source, target, obj1, obj2, mods, merge) {
367
391
  if (typeof mods === 'function' || Array.isArray(mods)) {
368
- this.set(target,
392
+ this.set(
393
+ target,
369
394
  _process(
370
395
  // clone what is picked
371
- JSON.parse(
372
- JSON.stringify(
373
- this.pick(source, obj1, false)
374
- )
375
- ),
396
+ JSON.parse(JSON.stringify(this.pick(source, obj1, false))),
376
397
  mods
377
- ), obj2, merge)
398
+ ),
399
+ obj2,
400
+ merge
401
+ )
378
402
  } else {
379
403
  merge = mods
380
404
  this.set(target, this.pick(source, obj1, false), obj2, merge)
@@ -406,7 +430,7 @@ DotObject.prototype.set = function (path, val, obj, merge) {
406
430
 
407
431
  for (i = 0; i < keys.length; i++) {
408
432
  key = keys[i]
409
- if (i === (keys.length - 1)) {
433
+ if (i === keys.length - 1) {
410
434
  if (merge && isObject(val) && isObject(obj[key])) {
411
435
  for (k in val) {
412
436
  if (hasOwnProperty.call(val, k)) {
@@ -445,14 +469,14 @@ DotObject.prototype.set = function (path, val, obj, merge) {
445
469
  *
446
470
  * var obj = {
447
471
  * "id": 1,
448
- * "some": {
449
- * "thing": "else"
450
- * }
472
+ * "some": {
473
+ * "thing": "else"
474
+ * }
451
475
  * }
452
476
  *
453
477
  * var transform = {
454
478
  * "id": "nr",
455
- * "some.thing": "name"
479
+ * "some.thing": "name"
456
480
  * }
457
481
  *
458
482
  * var tgt = dot.transform(transform, obj)
@@ -464,9 +488,11 @@ DotObject.prototype.set = function (path, val, obj, merge) {
464
488
  DotObject.prototype.transform = function (recipe, obj, tgt) {
465
489
  obj = obj || {}
466
490
  tgt = tgt || {}
467
- Object.keys(recipe).forEach(function (key) {
468
- this.set(recipe[key], this.pick(key, obj), tgt)
469
- }.bind(this))
491
+ Object.keys(recipe).forEach(
492
+ function (key) {
493
+ this.set(recipe[key], this.pick(key, obj), tgt)
494
+ }.bind(this)
495
+ )
470
496
  return tgt
471
497
  }
472
498
 
@@ -492,30 +518,33 @@ DotObject.prototype.dot = function (obj, tgt, path) {
492
518
  path = path || []
493
519
  var isArray = Array.isArray(obj)
494
520
 
495
- Object.keys(obj).forEach(function (key) {
496
- var index = isArray && this.useBrackets ? '[' + key + ']' : key
497
- if (
498
- (
521
+ Object.keys(obj).forEach(
522
+ function (key) {
523
+ var index = isArray && this.useBrackets ? '[' + key + ']' : key
524
+ if (
499
525
  isArrayOrObject(obj[key]) &&
500
- (
501
- (isObject(obj[key]) && !isEmptyObject(obj[key])) ||
502
- (Array.isArray(obj[key]) && (!this.keepArray && (obj[key].length !== 0)))
503
- )
504
- )
505
- ) {
506
- if (isArray && this.useBrackets) {
507
- return this.dot(obj[key], tgt, path.slice(0, -1).concat(path[path.length - 1] + index))
508
- } else {
509
- return this.dot(obj[key], tgt, path.concat(index))
510
- }
511
- } else {
512
- if (isArray && this.useBrackets) {
513
- tgt[path.join(this.separator).concat('[' + key + ']')] = obj[key]
526
+ ((isObject(obj[key]) && !isEmptyObject(obj[key])) ||
527
+ (Array.isArray(obj[key]) && !this.keepArray && obj[key].length !== 0))
528
+ ) {
529
+ if (isArray && this.useBrackets) {
530
+ var previousKey = path[path.length - 1] || ''
531
+ return this.dot(
532
+ obj[key],
533
+ tgt,
534
+ path.slice(0, -1).concat(previousKey + index)
535
+ )
536
+ } else {
537
+ return this.dot(obj[key], tgt, path.concat(index))
538
+ }
514
539
  } else {
515
- tgt[path.concat(index).join(this.separator)] = obj[key]
540
+ if (isArray && this.useBrackets) {
541
+ tgt[path.join(this.separator).concat('[' + key + ']')] = obj[key]
542
+ } else {
543
+ tgt[path.concat(index).join(this.separator)] = obj[key]
544
+ }
516
545
  }
517
- }
518
- }.bind(this))
546
+ }.bind(this)
547
+ )
519
548
  return tgt
520
549
  }
521
550
 
@@ -529,9 +558,8 @@ DotObject.str = wrap('str')
529
558
  DotObject.set = wrap('set')
530
559
  DotObject.delete = wrap('delete')
531
560
  DotObject.del = DotObject.remove = wrap('remove')
532
- DotObject.dot = wrap('dot')
533
-
534
- ;['override', 'overwrite'].forEach(function (prop) {
561
+ DotObject.dot = wrap('dot');
562
+ ['override', 'overwrite'].forEach(function (prop) {
535
563
  Object.defineProperty(DotObject, prop, {
536
564
  get: function () {
537
565
  return dotDefault.override
@@ -540,9 +568,8 @@ DotObject.dot = wrap('dot')
540
568
  dotDefault.override = !!val
541
569
  }
542
570
  })
543
- })
544
-
545
- ;['useArray', 'keepArray', 'useBrackets'].forEach(function (prop) {
571
+ });
572
+ ['useArray', 'keepArray', 'useBrackets'].forEach(function (prop) {
546
573
  Object.defineProperty(DotObject, prop, {
547
574
  get: function () {
548
575
  return dotDefault[prop]
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dot-object",
3
3
  "description": "dot-object makes it possible to transform and read (JSON) objects using dot notation.",
4
- "version": "2.1.0",
4
+ "version": "2.1.4",
5
5
  "author": {
6
6
  "name": "Rob Halff",
7
7
  "email": "rob.halff@gmail.com"
package/src/dot-object.js CHANGED
@@ -45,11 +45,23 @@ function isEmptyObject (val) {
45
45
  return Object.keys(val).length === 0
46
46
  }
47
47
 
48
+ var blacklist = ['__proto__', 'prototype', 'constructor']
49
+ var blacklistFilter = function (part) { return blacklist.indexOf(part) === -1 }
50
+
48
51
  function parsePath (path, sep) {
49
52
  if (path.indexOf('[') >= 0) {
50
- path = path.replace(/\[/g, '.').replace(/]/g, '')
53
+ path = path.replace(/\[/g, sep).replace(/]/g, '')
54
+ }
55
+
56
+ var parts = path.split(sep)
57
+
58
+ var check = parts.filter(blacklistFilter)
59
+
60
+ if (check.length !== parts.length) {
61
+ throw Error('Refusing to update blacklisted property ' + path)
51
62
  }
52
- return path.split(sep)
63
+
64
+ return parts
53
65
  }
54
66
 
55
67
  var hasOwnProperty = Object.prototype.hasOwnProperty
@@ -83,8 +95,7 @@ DotObject.prototype._fill = function (a, obj, v, mod) {
83
95
  var k = a.shift()
84
96
 
85
97
  if (a.length > 0) {
86
- obj[k] = obj[k] ||
87
- (this.useArray && isIndex(a[0]) ? [] : {})
98
+ obj[k] = obj[k] || (this.useArray && isIndex(a[0]) ? [] : {})
88
99
 
89
100
  if (!isArrayOrObject(obj[k])) {
90
101
  if (this.override) {
@@ -102,8 +113,7 @@ DotObject.prototype._fill = function (a, obj, v, mod) {
102
113
 
103
114
  this._fill(a, obj[k], v, mod)
104
115
  } else {
105
- if (!this.override &&
106
- isArrayOrObject(obj[k]) && !isEmptyObject(obj[k])) {
116
+ if (!this.override && isArrayOrObject(obj[k]) && !isEmptyObject(obj[k])) {
107
117
  if (!(isArrayOrObject(v) && isEmptyObject(v))) {
108
118
  throw new Error("Trying to redefine non-empty obj['" + k + "']")
109
119
  }
@@ -163,8 +173,10 @@ DotObject.prototype.object = function (obj, mods) {
163
173
  * @param {Function|Array} mod optional modifier
164
174
  */
165
175
  DotObject.prototype.str = function (path, v, obj, mod) {
176
+ var ok = parsePath(path, this.separator).join(this.separator)
177
+
166
178
  if (path.indexOf(this.separator) !== -1) {
167
- this._fill(path.split(this.separator), obj, v, mod)
179
+ this._fill(ok.split(this.separator), obj, v, mod)
168
180
  } else {
169
181
  obj[path] = _process(v, mod)
170
182
  }
@@ -193,7 +205,7 @@ DotObject.prototype.pick = function (path, obj, remove, reindexArray) {
193
205
  for (i = 0; i < keys.length; i++) {
194
206
  key = parseKey(keys[i], obj)
195
207
  if (obj && typeof obj === 'object' && key in obj) {
196
- if (i === (keys.length - 1)) {
208
+ if (i === keys.length - 1) {
197
209
  if (remove) {
198
210
  val = obj[key]
199
211
  if (reindexArray && Array.isArray(obj)) {
@@ -219,7 +231,9 @@ DotObject.prototype.pick = function (path, obj, remove, reindexArray) {
219
231
  }
220
232
  }
221
233
  if (remove && Array.isArray(obj)) {
222
- obj = obj.filter(function (n) { return n !== undefined })
234
+ obj = obj.filter(function (n) {
235
+ return n !== undefined
236
+ })
223
237
  }
224
238
  return obj
225
239
  }
@@ -277,7 +291,9 @@ DotObject.prototype._cleanup = function (obj) {
277
291
  keys = this.cleanup[i].split('.')
278
292
  root = keys.splice(0, -1).join('.')
279
293
  ret = root ? this.pick(root, obj) : obj
280
- ret = ret[keys[0]].filter(function (v) { return v !== undefined })
294
+ ret = ret[keys[0]].filter(function (v) {
295
+ return v !== undefined
296
+ })
281
297
  this.set(this.cleanup[i], ret, obj)
282
298
  }
283
299
  this.cleanup = []
@@ -334,13 +350,21 @@ DotObject.prototype.move = function (source, target, obj, mods, merge) {
334
350
  * @param {Function|Array} mods
335
351
  * @param {Boolean} merge
336
352
  */
337
- DotObject.prototype.transfer = function (source, target, obj1, obj2, mods, merge) {
353
+ DotObject.prototype.transfer = function (
354
+ source,
355
+ target,
356
+ obj1,
357
+ obj2,
358
+ mods,
359
+ merge
360
+ ) {
338
361
  if (typeof mods === 'function' || Array.isArray(mods)) {
339
- this.set(target,
340
- _process(
341
- this.pick(source, obj1, true),
342
- mods
343
- ), obj2, merge)
362
+ this.set(
363
+ target,
364
+ _process(this.pick(source, obj1, true), mods),
365
+ obj2,
366
+ merge
367
+ )
344
368
  } else {
345
369
  merge = mods
346
370
  this.set(target, this.pick(source, obj1, true), obj2, merge)
@@ -365,16 +389,16 @@ DotObject.prototype.transfer = function (source, target, obj1, obj2, mods, merge
365
389
  */
366
390
  DotObject.prototype.copy = function (source, target, obj1, obj2, mods, merge) {
367
391
  if (typeof mods === 'function' || Array.isArray(mods)) {
368
- this.set(target,
392
+ this.set(
393
+ target,
369
394
  _process(
370
395
  // clone what is picked
371
- JSON.parse(
372
- JSON.stringify(
373
- this.pick(source, obj1, false)
374
- )
375
- ),
396
+ JSON.parse(JSON.stringify(this.pick(source, obj1, false))),
376
397
  mods
377
- ), obj2, merge)
398
+ ),
399
+ obj2,
400
+ merge
401
+ )
378
402
  } else {
379
403
  merge = mods
380
404
  this.set(target, this.pick(source, obj1, false), obj2, merge)
@@ -406,7 +430,7 @@ DotObject.prototype.set = function (path, val, obj, merge) {
406
430
 
407
431
  for (i = 0; i < keys.length; i++) {
408
432
  key = keys[i]
409
- if (i === (keys.length - 1)) {
433
+ if (i === keys.length - 1) {
410
434
  if (merge && isObject(val) && isObject(obj[key])) {
411
435
  for (k in val) {
412
436
  if (hasOwnProperty.call(val, k)) {
@@ -445,14 +469,14 @@ DotObject.prototype.set = function (path, val, obj, merge) {
445
469
  *
446
470
  * var obj = {
447
471
  * "id": 1,
448
- * "some": {
449
- * "thing": "else"
450
- * }
472
+ * "some": {
473
+ * "thing": "else"
474
+ * }
451
475
  * }
452
476
  *
453
477
  * var transform = {
454
478
  * "id": "nr",
455
- * "some.thing": "name"
479
+ * "some.thing": "name"
456
480
  * }
457
481
  *
458
482
  * var tgt = dot.transform(transform, obj)
@@ -464,9 +488,11 @@ DotObject.prototype.set = function (path, val, obj, merge) {
464
488
  DotObject.prototype.transform = function (recipe, obj, tgt) {
465
489
  obj = obj || {}
466
490
  tgt = tgt || {}
467
- Object.keys(recipe).forEach(function (key) {
468
- this.set(recipe[key], this.pick(key, obj), tgt)
469
- }.bind(this))
491
+ Object.keys(recipe).forEach(
492
+ function (key) {
493
+ this.set(recipe[key], this.pick(key, obj), tgt)
494
+ }.bind(this)
495
+ )
470
496
  return tgt
471
497
  }
472
498
 
@@ -492,30 +518,33 @@ DotObject.prototype.dot = function (obj, tgt, path) {
492
518
  path = path || []
493
519
  var isArray = Array.isArray(obj)
494
520
 
495
- Object.keys(obj).forEach(function (key) {
496
- var index = isArray && this.useBrackets ? '[' + key + ']' : key
497
- if (
498
- (
521
+ Object.keys(obj).forEach(
522
+ function (key) {
523
+ var index = isArray && this.useBrackets ? '[' + key + ']' : key
524
+ if (
499
525
  isArrayOrObject(obj[key]) &&
500
- (
501
- (isObject(obj[key]) && !isEmptyObject(obj[key])) ||
502
- (Array.isArray(obj[key]) && (!this.keepArray && (obj[key].length !== 0)))
503
- )
504
- )
505
- ) {
506
- if (isArray && this.useBrackets) {
507
- return this.dot(obj[key], tgt, path.slice(0, -1).concat(path[path.length - 1] + index))
508
- } else {
509
- return this.dot(obj[key], tgt, path.concat(index))
510
- }
511
- } else {
512
- if (isArray && this.useBrackets) {
513
- tgt[path.join(this.separator).concat('[' + key + ']')] = obj[key]
526
+ ((isObject(obj[key]) && !isEmptyObject(obj[key])) ||
527
+ (Array.isArray(obj[key]) && !this.keepArray && obj[key].length !== 0))
528
+ ) {
529
+ if (isArray && this.useBrackets) {
530
+ var previousKey = path[path.length - 1] || ''
531
+ return this.dot(
532
+ obj[key],
533
+ tgt,
534
+ path.slice(0, -1).concat(previousKey + index)
535
+ )
536
+ } else {
537
+ return this.dot(obj[key], tgt, path.concat(index))
538
+ }
514
539
  } else {
515
- tgt[path.concat(index).join(this.separator)] = obj[key]
540
+ if (isArray && this.useBrackets) {
541
+ tgt[path.join(this.separator).concat('[' + key + ']')] = obj[key]
542
+ } else {
543
+ tgt[path.concat(index).join(this.separator)] = obj[key]
544
+ }
516
545
  }
517
- }
518
- }.bind(this))
546
+ }.bind(this)
547
+ )
519
548
  return tgt
520
549
  }
521
550
 
@@ -529,9 +558,8 @@ DotObject.str = wrap('str')
529
558
  DotObject.set = wrap('set')
530
559
  DotObject.delete = wrap('delete')
531
560
  DotObject.del = DotObject.remove = wrap('remove')
532
- DotObject.dot = wrap('dot')
533
-
534
- ;['override', 'overwrite'].forEach(function (prop) {
561
+ DotObject.dot = wrap('dot');
562
+ ['override', 'overwrite'].forEach(function (prop) {
535
563
  Object.defineProperty(DotObject, prop, {
536
564
  get: function () {
537
565
  return dotDefault.override
@@ -540,9 +568,8 @@ DotObject.dot = wrap('dot')
540
568
  dotDefault.override = !!val
541
569
  }
542
570
  })
543
- })
544
-
545
- ;['useArray', 'keepArray', 'useBrackets'].forEach(function (prop) {
571
+ });
572
+ ['useArray', 'keepArray', 'useBrackets'].forEach(function (prop) {
546
573
  Object.defineProperty(DotObject, prop, {
547
574
  get: function () {
548
575
  return dotDefault[prop]
@@ -167,4 +167,10 @@ describe('Dotted Array notation', function () {
167
167
  describe('with bracket notation', function () {
168
168
  runVariant('bracket')
169
169
  })
170
+
171
+ describe('Refuse to update __proto__', function () {
172
+ var obj = { path: [] }
173
+
174
+ ;(() => Dot.set('path[0].__proto__.toString', 'test', obj)).should.throw(/Refusing to update/)
175
+ })
170
176
  })
package/test/dot-json.js CHANGED
@@ -55,6 +55,28 @@ describe('Object test:', function () {
55
55
  })
56
56
  })
57
57
 
58
+ it('Should expand dotted keys with array notation with different separator', function () {
59
+ var row = {
60
+ id: 2,
61
+ my_arr_0: 'one',
62
+ my_arr_1: 'two',
63
+ my_arr_2: 'three',
64
+ 'my_arr2[0]': 'one',
65
+ 'my_arr2[1]': 'two',
66
+ 'my_arr2[2]': 'three'
67
+ }
68
+
69
+ new Dot('_').object(row)
70
+
71
+ row.should.eql({
72
+ id: 2,
73
+ my: {
74
+ arr: ['one', 'two', 'three'],
75
+ arr2: ['one', 'two', 'three']
76
+ }
77
+ })
78
+ })
79
+
58
80
  it('Should allow keys with numbers', function () {
59
81
  var row = {
60
82
  id: 2,
@@ -205,4 +227,11 @@ describe('Object test:', function () {
205
227
 
206
228
  row.should.eql({ page: { name: 'my_page' } })
207
229
  })
230
+
231
+ it('Dot.object should disallow to set __proto__', function () {
232
+ var row = { '__proto__.toString': 'hi' }
233
+
234
+ var dot = new Dot()
235
+ ;(() => dot.object(row)).should.throw(/Refusing to update/)
236
+ })
208
237
  })
package/test/dot.js CHANGED
@@ -7,6 +7,8 @@ var pkg = require('./fixtures/package.json')
7
7
  describe('dot():', function () {
8
8
  var obj
9
9
 
10
+ // Dot.useBrackets = false;
11
+
10
12
  beforeEach(function () {
11
13
  obj = {
12
14
  id: 'my-id',
@@ -36,7 +38,25 @@ describe('dot():', function () {
36
38
  ehrm: 123,
37
39
  dates: {
38
40
  first: new Date('Mon Oct 13 2014 00:00:00 GMT+0100 (BST)')
39
- }
41
+ },
42
+ arrays: [
43
+ [
44
+ [
45
+ {
46
+ all: [
47
+ [
48
+ {
49
+ the: [
50
+ 'way',
51
+ ['down']
52
+ ]
53
+ }
54
+ ]
55
+ ]
56
+ }
57
+ ]
58
+ ]
59
+ ]
40
60
  }
41
61
  })
42
62
 
@@ -50,7 +70,9 @@ describe('dot():', function () {
50
70
  'some.array[0]': 'A',
51
71
  'some.array[1]': 'B',
52
72
  ehrm: 123,
53
- 'dates.first': new Date('Mon Oct 13 2014 00:00:00 GMT+0100 (BST)')
73
+ 'dates.first': new Date('Mon Oct 13 2014 00:00:00 GMT+0100 (BST)'),
74
+ 'arrays[0][0][0].all[0][0].the[0]': 'way',
75
+ 'arrays[0][0][0].all[0][0].the[1][0]': 'down'
54
76
  }
55
77
 
56
78
  Dot.dot(obj).should.eql(expected)
@@ -72,7 +94,8 @@ describe('dot():', function () {
72
94
  }],
73
95
  'some.array': ['A', 'B'],
74
96
  ehrm: 123,
75
- 'dates.first': new Date('Mon Oct 13 2014 00:00:00 GMT+0100 (BST)')
97
+ 'dates.first': new Date('Mon Oct 13 2014 00:00:00 GMT+0100 (BST)'),
98
+ arrays: JSON.parse(JSON.stringify(obj.arrays))
76
99
  }
77
100
 
78
101
  Dot.keepArray = true
@@ -92,10 +115,32 @@ describe('dot():', function () {
92
115
  'some.array[0]': 'A',
93
116
  'some.array[1]': 'B',
94
117
  ehrm: 123,
95
- 'dates.first': new Date('Mon Oct 13 2014 00:00:00 GMT+0100 (BST)')
118
+ 'dates.first': new Date('Mon Oct 13 2014 00:00:00 GMT+0100 (BST)'),
119
+ 'arrays[0][0][0].all[0][0].the[0]': 'way',
120
+ 'arrays[0][0][0].all[0][0].the[1][0]': 'down'
121
+ }
122
+
123
+ Dot.dot(obj).should.eql(expected)
124
+ })
125
+
126
+ it('useBrackets wrap indexes without brackets', function () {
127
+ var expected = {
128
+ id: 'my-id',
129
+ 'nes.ted.value': true,
130
+ 'other.nested.stuff': 5,
131
+ 'nested.array.0.with': 'object1',
132
+ 'nested.array.1.and': 'object2',
133
+ 'some.array.0': 'A',
134
+ 'some.array.1': 'B',
135
+ ehrm: 123,
136
+ 'dates.first': new Date('Mon Oct 13 2014 00:00:00 GMT+0100 (BST)'),
137
+ 'arrays.0.0.0.all.0.0.the.0': 'way',
138
+ 'arrays.0.0.0.all.0.0.the.1.0': 'down'
96
139
  }
97
140
 
141
+ Dot.useBrackets = false
98
142
  Dot.dot(obj).should.eql(expected)
143
+ Dot.useBrackets = true
99
144
  })
100
145
 
101
146
  it('Always keeps empty arrays', function () {
package/test/str.js CHANGED
@@ -24,6 +24,28 @@ describe('str:', function () {
24
24
  })
25
25
  })
26
26
 
27
+ it('can set nested with array notation', function () {
28
+ var obj = {
29
+ a: 1
30
+ }
31
+ Dot.str('object.fields[0].subfield', 'value', obj)
32
+ Dot.str('object.fields[1].subfield', 'value1', obj)
33
+
34
+ obj.should.deepEqual({
35
+ a: 1,
36
+ object: {
37
+ fields: [
38
+ {
39
+ subfield: 'value'
40
+ },
41
+ {
42
+ subfield: 'value1'
43
+ }
44
+ ]
45
+ }
46
+ })
47
+ })
48
+
27
49
  it('can set root level property regardless whether override is set', function () {
28
50
  Dot.str('a', 'b', {
29
51
  a: 1
@@ -31,4 +53,11 @@ describe('str:', function () {
31
53
  a: 'b'
32
54
  })
33
55
  })
56
+
57
+ it('cannot set __proto__ property', function () {
58
+ (() => Dot.str('__proto__.toString', 'hi', {})).should.throw(
59
+ /Refusing to update/
60
+ );
61
+ ({}.toString().should.deepEqual('[object Object]'))
62
+ })
34
63
  })