Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug with numeric object keys in arrays #82

Open
mugendi opened this issue Feb 13, 2023 · 0 comments
Open

Bug with numeric object keys in arrays #82

mugendi opened this issue Feb 13, 2023 · 0 comments

Comments

@mugendi
Copy link

mugendi commented Feb 13, 2023

I found a bug with handling numeric object keys within arrays.
This occurs when you convert an object with such keys into dot notation and attempt to convert it back to an object.

Here is code to demonstrate what I mean:

const dotObject = require('dot-object');
let data = {
    a:2,
    arr: [
        { "6": "number six" }
    ],
    "4":"555"
};

console.log(data);
let flattened = dotObject.dot(data);
console.log(flattened);
let obj = dotObject.object(flattened);
console.log(obj);

This will log the following:

{ '4': '555', a: 2, arr: [ { '6': 'number six' } ] }
{ '4': '555', a: 2, 'arr[0].6': 'number six' }
{ '4': '555', a: 2, arr: [ [ <6 empty items>, 'number six' ] ] }

Notice that the object { "6": "number six" } is converted to an array where 6 is the array index.

Found a fix

I investigated the issue and found that the issue is with the isIndex method in the index.js since it parses all digits as array indexes.

My fix was to pad array indexes with "⁈" and "⁉" so that the path generated by parsePath looks like arr/⁈0⁉/6 and not arr/0/6 which differentiates the numeric object key and array index.

function parsePath (path, sep) {
  // in the event one should have "⁈" in their keys
  if (path.indexOf('⁈') >= 0) {
      path = path.replace(//g, '⁈⁈');
  }
  // in the event one should have "⁉" in their keys
  if (path.indexOf('⁉') >= 0) {
      path = path.replace(//g, '⁉⁉');
  }
  // pad array indexes with "⁈" and "⁉" so that 0=>"⁈0⁉"
  if (path.indexOf('[') >= 0) {
      path = path.replace(/\[/g, sep + '⁈').replace(/]/g, '⁉');
  }

  var parts = path.split(sep)
  var check = parts.filter(blacklistFilter)
  if (check.length !== parts.length) {
    throw Error('Refusing to update blacklisted property ' + path)
  }
  return parts
}

This means that we now check for indexes as shown below:

function isIndex (k) {
  return /^⁈\d+⁉$/.test(k)
}

And finally, to avoid spitting out ⁈0⁉ in objects I added a regex to remove the index padding so that _.fill method now starts with:

DotObject.prototype._fill = function (a, obj, v, mod) {
  var j = a.shift()
  var k = j.replace(/[⁈⁉]/g,'');
   ...
}

Results

...
let data = {
    a:2,
    arr: [
        { "6": "number six" },
        {'⁈0⁉': "weird key"}
    ],
    "4":"555"
};
console.log(data);
let flattened = dotObject.dot(data);
let obj = dotObject.object(flattened);
console.log(obj); 
//=> { '4': '555', a: 2, arr: [ { '6': 'number six' }, { '⁈0⁉': 'weird key' }  ] 

This might be too 'hacky'

I'm not sure if there is a better fix for this issue so I'm raising an issue as well as contributing my solution to get the conversation started.
If this is the best solution, then I'm ready to submit a PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant