Giter Club home page Giter Club logo

object-path's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

object-path's Issues

Inconsistent behaviour in empty method.

I read about this test and don't understand why exist.

it('should ignore invalid arguments safely', function(){
    var obj = {};
    // 1
    expect(objectPath.empty()).to.equal(void 0);
    // 2
    expect(objectPath.empty(obj, 'path')).to.equal(void 0);
    // 3
    expect(objectPath.empty(obj, '')).to.equal(obj);

    obj.path = true;
    // 4
    expect(objectPath.empty(obj, 'inexistant')).to.equal(obj);
});

2nd an 4th assertions are essentialy the same thing. 
In second assertion `obj` is an object and `path` property does not exist in `obj`.
In fourth assertion `obj` is an object and `existant` property does not exist in `obj`

I think that it should return the same value `undefined` or the same `object` passed.

document browser support?

Hey there,

It looks like this module works in ie8. Also: after peeping the sauce it doesn't look like there would be any reason for it not to. What is the stance on browser support?

bower needs tags

I forgot to ask one more thing, bower needs tags to be pushed. so if you could git tag 0.3.0 then git push origin --tags, at least for the last version

Question on "doNotReplace" in "set" method

I'd like to use this to determine by a boolean whether the "set" operation should take effect. Two questions:

  1. this isn't documented, so i wanted to ask if this is an official feature, or not meant to be used
  2. if "doNotReplace" evaluates to truthy, would it make sense this is first tested before traversing down? or am i misunderstanding the usage of "doNotReplace"?

Thanks!

Question/Enhancement: Return nested values from array

Suppose I have a object like this:

const obj = { tags: [ {name: 'one'}, {name: 'two'}, {name: 'three'}, ] }

I read from the API that you can get a single value of a known index:
ObjectPath.get(obj,'tags.1.name') // returns 'two'

But does object-path allow for a path that can map the nested 'name' value?

e.g.
ObjectPath.get(obj,'tags.*.name') // returns ['one','two','three']

Thanks

identify array element by ID field, instead of by its index

I have a complex hierarchy consisting of elements identified by an ID property, which makes traversing the tree easier than by index

{
   "personas": [
        { "id": "abc", "name": "John" }, 
        { "id:"def", "name":"Mike" },...
    ]
}

I would like to use a syntax like personas.id:def:name or personas[id:def].name to traverse the path instead of personas.1.name.

Add some benchmarks

At least to track any performance regression introduced during development

get(global, 'navigator.userAgent') === undefined

ObjectPath.get(global, 'navigator.userAgent') // undefined

const Navigator = ObjectPath.get(global, 'navigator') // Navigator
ObjectPath.get(Navigator, 'userAgent') // undefined

navigator.userAgent // Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 ...
navigator['userAgent'] // Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 ...

Cannot set object with number in path e.g. 'a.2008'

I want to set an object as follows:

let emptyObj = {}
const path = 'a.2008'
const value = [1,2,3,4]
objectPath.set(emptyObj, path, value)

I expect the object to look like:

emptyObject = {
  a: {
    2008: [1, 2, 3, 4],
  }
}

Instead the object looks like this:

{
    "a": [
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        ...(2008x),
       [1, 2, 3, 4]
    ],
}

improvement to coalesce function

hey @mariocasciaro I stumbled upon a common use case (at least for me) that I need to check a series of objects and return the first non undefined value. I'm doing a really dynamic app in AngularJS and I have a huge object that has many members, that depending on the current 'object mode', I need to coalesce many objects at the same time. So I was doing this:

objectPath.coalesce(
   obj, 
   ['item.desc','plan.type.desc'], 
   object.coalesce(
      plans,
      ['slug','item.title']
   )
);

so, instead of having this over and over, I decided to improve it a bit, to accept an array as the first parameter (really heavy "overload" in the programming sense):

objectPath.coalesce([
  [obj, ['item.desc','plan.type.desc']],
  [plans, ['slug','item.title']]
], "this is ignored", null);

do you want me to PR this feature? because I'm using it 'internally' right now, not sure if people would use. the syntax is a bit shady, an array of arrays is not pretty, but it's straight forward. an object could be used, but maybe it's overkill

the code is in https://github.com/pocesar/object-path/blob/coalesce-array/index.js#L136-L145
the tests are in https://github.com/pocesar/object-path/blob/coalesce-array/test.js#L254-L280

del() not executing on properties set to 'null'

There seems to be an issue with deleting null objects. I can't seem to find documentation on how this should be done.
I expected objectPath.del() to work on any path regardless of the value of the property.
Consider this:

var objectPath = require("object-path")
obj = { a: 1234, b: 12, c: null }
objectPath.del(obj, 'b')
// this behaves correctly as I expect
//returns { a: 1234, c: null }
// obj ==== { a: 1234, c: null }

objectPath.del(obj, 'c')
// this does not return a result nor modifies the obj
// returns null
//obj === { a: 1234, b: 12, c: null }

Likewise, I noticed .empty() has the same effect. I'm assuming internally it uses .del()

Is there anything I'm doing wrong?

Last version broke the previous functionality

Well, I found a bug with the last patch. I have an object var any = {};.
I need it to be:

var any['1']['1'] = {};

using ensureExists like this:

var 
  sectionId = 1,
  sections = [/* array */];
objectPath.ensureExists(any, [sectionId.toString(),sections[sectionId].questionId.toString()], {});

its yielding:

// reproducible test case
// var any = {}; 
// objectPath.ensureExists(any, ['1','1'], {});
// expect(any).to.be.an('object'); << ok
// expect(any[1]).to.be.an('object'); << failing
// expect(any[1][1]).to.be.an('object'); << ok
[undefined, Object{ }]

close but no cigar. it should especifically check if it's using an string and don't assume a number unless it's really a number

the version should either rollback the changes or apply an emergency patch 0.8.1

Missing support for ES2015 Map and Set

The code doesn't seem to work when the underlying object (or an object along the path) is of type Set or Map.

We could support both by following this approach:

  • with Set, convert it into an array and access it as it is an array (some logic and memory considerations need to be made here)
  • with Map, you can simply use the get and has fields to access the data.

Code to replicate the issue:

var objectPath = require("object-path");

var s = new Set(['a','b','c']);
console.log(objectPath.get(s, '0')); // undefined
console.log((Array.from(s))[0]); // 'a'

var m = new Map();
m.set('a','b');
console.log(objectPath.get(m, 'a')); // undefined
console.log(m.get('a')); // 'b'

A gotcha that might be worth addressing somehow: set() with path=""

I guess I wasn't thinking straight when doing this, but I had some code that did objectPath.get(obj.foo, path) and this yields a sensible result when path is "": you get obj.foo

However, then I had code that tried to use set() also with the same path, and that obviously does not work well because it can't change the original reference passed to the method, but probably updates a new object that gets thrown away since nothing is referencing it:

var objectPath = require('object-path');
var a = { b: { c: 1 } };
objectPath.get(a.b, ""); // returns { c: 1 }
objectPath.set(a.b, "", "hi"); // returns { c: 1 } - but a.b is still { c: 1 }, not "hi"
objectPath.set(a, "b", "hi"); // returns { c: 1 } AND a.b. is set to "hi"

As a work-around I ended up doing something like (I did this to preserve other references to the same 'obj' elsewhere):

if (path == "")
{
  // quick hack for objects
  for (var p in obj) delete obj[p];
  for (var p in value) obj[p] = value[p];
}
else
  objectPath.set(obj, path, value);

Obviously this would only work for objects and noe value types, so I'm not sure what a consistent solution here is.

Since it now just passes silently but does not do what one intends, maybe an error should be thrown instead if the path is blank?

20 tests fail with chai 4.1.2

In debian we are about to update chai from 3.5.0 to 4.1.2 and some tests are failing with object-path, see: https://bugs.debian.org/884155

Here is a sample failure:

  1) set should set value under shallow object:
     AssertionError: expected { Object (a, b, ...) } to have deep property 'c.m'
      at Context.<anonymous> (/root/node-object-path/test.js:164:30)                         
      at callFn (/usr/lib/nodejs/mocha/lib/runnable.js:223:21)                               
      at Test.Runnable.run (/usr/lib/nodejs/mocha/lib/runnable.js:216:7)                     
      at Runner.runTest (/usr/lib/nodejs/mocha/lib/runner.js:373:10)                         
      at /usr/lib/nodejs/mocha/lib/runner.js:451:12                                          
      at next (/usr/lib/nodejs/mocha/lib/runner.js:298:14)                                   
      at /usr/lib/nodejs/mocha/lib/runner.js:308:7                                           
      at next (/usr/lib/nodejs/mocha/lib/runner.js:246:23)                                   
      at Immediate.<anonymous> (/usr/lib/nodejs/mocha/lib/runner.js:275:5)                   
      at runCallback (timers.js:672:20)                                                      
      at tryOnImmediate (timers.js:645:5)                                                    
      at processImmediate [as _immediateCallback] (timers.js:617:5)

do you have an idea why ? Do you plan to move to chai 4.1.2 ?

Thanks, Paolo

.has(/* nothing */) should be true

code on

object-path/index.js

Lines 160 to 162 in c540af3

if (isEmpty(path) || path.length === 0) {
return false;
}
for the .has() method:

    if (isEmpty(path) || path.length === 0) {
      return false;
    }

If we are searching for an empty key and the variable being searched is an object, then it is intuitive that the object has that. It can perhaps miss all keys in the world as long as long as they have a name, but for keys with no name any object has all.

`del` method behaves differently on arrays than `delete` operator

The delete operator does not splice from or otherwise modify the length of arrays. It removes that key, but the other elements retain their index.

object-path's del method instead uses splice (index.js#L124), which modifies the length of the array and changes the index of all elements after the deleted element.

For my use case, I would like to use the normal delete operator behavior. This would be a breaking change though, so I'm unsure what the best way of approaching this change would be.

Source: MDN Article on the delete operator

Method set in simple paths

When it is passed a simple path to set method I expect to have the same behaviour of expression:

obj[path] = value

Examples:

var obj = {}
objectPath.set(obj, 3, 'foo') // now obj is {3: 'foo'}
// or
var obj = {}
obj[3] = 'foo'
var obj = {}
objectPath.set(obj, 'a', 'foo') // now obj is {a: 'foo'}
// or
var obj = {}
obj['a'] = 'foo' // now obj is {a: 'foo'}

But exist in set method one case that it behaves different:

var obj = {}
objectPath.set(obj, '', 'foo') // now obj is {}
// however
var obj = {}
obj[''] = 'foo' // now obj is {'': 'foo'}

I think that it would be a good idea change behaviour in this case to keep the consistency. I think the same for another methods.

coalesce with falsy

Hi. I'm finding myself using coalesce for achieving clean and idiomatic code. But sometimes my data providers return me objects, where some keys I pick present, but falsy (undefined, null, empty string etc). In the mean time coalesce relies on key existing/non-existing.

Is it possible to implement in this module another variant of coalesce which will check not key presence, but its value falsiness? So, it will work like good old object.key || object.key2 || ... but with benefits of deep paths support.

I've looked through opened & closed issues, but found nothing similar. If it is a dulicate, please, forgive me. I think other users of object-path could face this issue as well, and it's not pleasant to return to ||-stuff when you're already using such powerful utility like this.

Future add-ons

Leaving a clear way to add functionality to object-path without having to hack it (like in cases #30, #22, #21, #18), so it can be extended like lodash does. it has a lot of utility built-in, and you can for example, extend it to use fast.js using internally through _.mixin, like this for example https://github.com/marklagendijk/lodash-deep

var _ = require("lodash");
_.mixin(require("lodash-deep"));

so whenever someone come up with a new functionality, he can just snap it in object-path without hassle. it would expose the internal functions of objectPath to the mixin constructor (like get, del, set, isEmpty, etc)

The point is, the library managed to get 164.000 downloads in a month, which is pretty nice and people are actually using it, so the argument is based on the number of people that could improve it without adding it to core

Array indices in .set

Hello! Thanks for the great module!

I'm confused with the behaviour of the .set method. I expect that when I do something like this:

objectPath.set(obj, "a.0.b", "value")

I will get the following structure:

{ a: [ { b: "value" } ] }

Instead I'm getting:

{ a: { '0': [ b: 'value' ] } }

I believe that's incorrect, because it is setting named properties of arrays treating array indices as object keys at the same time.
If this is an intended behaviour, then, what path should I pass to .set to get the structure like in the first example?
Probably, there should be a special syntax for array indices, e.g.:

objectPath.set(obj, "a[0].b", "value")

I can submit a patch for this (probably, next week), if it's OK to add this functionality.

Thank you!

Sparse arrays are being created when using objectPath.set

Need to report it, I was using version 0.7.0 on my angular app (it's really complex, and use objectPath extensively), and it uses JSON responses as well. sometimes, JSON string numbers get translated to number literals coming from PHP. this makes objectPath.set/get (on version 0.8.0) a nightmare. Now I'm randomly getting sparse arrays on my app, so I'm having to explicitly use objectPath.set(obj, [somewhere, someId.toString()]); everywhere =/ and now it sometimes throw, because someId might not be defined.

another example objectPath.set(sections.display.joined,[where, id].join("."), item); is creating the following item:

activities [undefined, undefined, undefined, 2 more...]

Because sometimes I have the where being a full path like "some.path", so I need to join them, so it becomes "some.path.10", but the behavior changed drastically, I have near 700 calls to objectPath throrough my app, and around 500k lines, so I'll have to stick to 0.7.0 for now. I'd have to make a objectPath.ensureExist to each intermediary object and make it an object before calling set on it, but this defeats the purpose of the module

Organization

Since object-path 1.0+ will revolve around plugins instead of PRs, what about object-path becomes an organization, and all plugins can go inside that? See #36 (comment)

https://github.com/object-path is available ;)

it can have it's own repo for it's page, better docs, can add collaborators to the team, have a finer grain for issues, etc

Improvement escaped dots

According to the most arrogant ****head I've ever encountered in Github so far, stating "Please do more research and have something to back up your words before you waste someone's time like this." when I said that object-path already had what he is "reinventing" (littering npm with an useless module called set-value).

object-path is missing a way to handle keys with escaped dots in it. it already does when you use the array notation (eg: ['some.dot.key', 'another.path']) and only a retarded person (IMHO) would write it as objectPath.get(obj, 'some\.****head\.is\.stupid');

sorry for the rant along, but it's amazing how people can be stupid now a days

An object key starting with a number cannot be deleted using `op.del`

From what I can see if I have an object key defined as a number, it is unable to be deleted using op.del

import op from 'object-path';

let users = {
  '12345678': {
    name: 'Mr Bob'
  }
}

op.del(users, 'users.12345678'); // should delete user object
op.get(users, 'users.12345678'); // returns user object

// scenario that works
let cats = {
  'user_12345678': {
    name: 'Mr Meow'
  }
}

op.del(cats, 'user_12345678'); // should delete user object
op.get(cats, 'user_12345678'); // returns undefined as expected

I would be happy to take this onboard and try to fix if you are still taking contributions.

Coalesce

hey @mariocasciaro would you like a coalesce function for object-path? Returns the first non-falsy value from an array of paths:

var obj = {
  might: { have: 'this prop' },
};
objectPath.coalesce(obj, ['might.not.have', 'might.have']); // returns 'this prop'

if you'd want this in core, I can PR to you. it's merely a helper loop function of a series of .get calls and breaking on the first truthy value (although it currently checks for FALSE, but will skip undefined and null)

set/ensureExists doesn't set child property if parent has non-object a value

I would expect that

var o = { a: 'asdf' };
objectPath.ensureExists(o, 'a.b', 'bsdf');
console.log(o);

would result in {a: {b: 'bsdf'} } but the result is {a: 'asdf' }. This doesn't seem to work with objectPath.set() either. Is this intended behavior or is there another way I could make this work without having to check objectPath.has(o, 'a.b')?

Implement concat

Please consider implementing a concat method so that multiple elements can be added to an array at once without a loop.

objectPath.delete(obj, path) support

First of all, stoked you wrote this - was about to have to write it myself. Any chance of adding .delete(obj, path) support? If you're too busy, let me know and I'll fork and PR it when I get a chance.

๐Ÿ‘

How about objectPath.splice?

Object-path's get, set, delete and push works well with array, but I can't insert something into the middle of array.

How about implementing the splice?

[Question] What is the use of getKey

After reading your code, I have one confusion about the implementation of getKey

function getKey(key){
    var intKey = parseInt(key);
    if (intKey.toString() === key) {
        return intKey;
    }
    return key;
} 

Can someone explain a bit ? I mean I know what this function does. But why we have to use getKey to assign the value to something like currentPath as below

var currentPath = getKey(path[0]);

feature

I am new to this library , i just want check if we can get the object-path based on a value i provide ?

Dot values in keys?

var obj = {
  a: {
    b: "d",
    c: ["e", "f"],
    '\u1200': 'unicode key',
    'dot.dot': 'key'
  },
  "x.y":"doesn't work"
};

objectPath.get(obj, ["x.y"]);

"doesn't work"

objectPath.get(obj, "x.y"); // This one doesn't work, and I would think it should :(
objectPath.get(obj, "a.dot.dot"); // This one doesn't work, and I would think it should :(

Can't see any reason why it wouldn't fallback to finding a['dot.dot'] if a.dot.dot is not defined. Am I missing something?

:)

Dots in property names

Nice package, but what I should do, to make it work with property names, that contains dots?

For example:

var objectPath = require("object-path");
var a = {};
objectPath.set(a, 'a\.b', 1);
// a now equals {a: {b: 1} }

But shouldn't it be equal { 'a.b': 1 }?

has doesn't work with sparse arrays

Hey, I've noticed that has throws an error when I try to check a nested path in a sparse array. I believe it should return false in this case.

Example:
objectPath.has({ foo: [undefined, undefined, undefined] }, 'foo.0.bar')

Throws:

 Uncaught TypeError: Cannot convert undefined or null to object(โ€ฆ)
 objectPath.has @ index.js:136

Default value can be a callback or the fourth parameter of .get()

I need to emit an event when the object is malformed.
Now i'm using a specific default value and i test if this value and emit the event.

For the callback, it can be nice if the first the parameter is an error with the current attribute name undefined or a string of this attribute name.

I can do a PR if you need.

exists with wildcards

So, I was checking for a cache entry, and the cache keys are completly random, but I knew the id of the cache item, basically it was like this:

cache = {
 activities: {
   'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad': [
    {'id': 1 /*...*/},
    {'id': 9 /*...*/},
    /* ...etc */
  ]
 }
};

I could just iterate through all activities, and check each one of the ids, but then I realized that I could use an 'exists' function that could 'ignore' parts of the path (using a * and check for the existance of the deep path).
So, for that cache I'd do objectPath.exists(cache, 'activities.*.*.id', 1) the last value is a comparision. If omitted, it just check of the path !== undefined. It's a nice addition to the library, what do you think @mariocasciaro ?

objectPath.empty

it's me again ๐ŸŽฑ
interested in adding a "empty" method, that empties the given path, like objectPath.empty(obj,'some.path')

  • if it's an array, remove all the items but not the reference, aka, doesn't reassign an empty array to it , most likely do a .length = 0; to it
  • if it's string, make it ''
  • if it's object, delete all the members, but keep the reference (like arrays)
  • if number, make it 0
  • if boolean, false, etc

Get property itself not value of property

Hi,
Can I use this utility to get the property itself rather than value?

For instance, I have a string path to a property, I want to delete that property from an object, so using this utility to find the property by string path, I get only its value and not a reference to it to use it later.

Any idea?
Thanks

Return the result of a function property

Hi,

I think it would be really nice to detect if a property is a function and return it's result.
It could be handy when you want get a value out of a getter.

If you still want to get the function itself, it could be specified via an optional parameter to get.
You could also create another method that does this, like fetch or getOrCall.

What do you think?
Thanks!

Enhancement: move

objectPath.move(obj, 'old.path', 'new.path');

instead of:

 const path = objectPath.get(obj, 'old.path');
 objectPath.set(obj, 'new.path', path);
 objectPath.del(obj, 'old.path');

Behavior change (explicit throw)

I'm inclined to throw an error (or an specialized error, like ObjectPathError) when the provided path is empty. It's usually a programming mistake, and it bit me a couple of times (usually when dealing with JSON coming from the server). Returning the original object shouldn't be the right thing to do, since it can be 'truthy'.

See #60, #59 and #54

Examples:

var ok;

Ok = 'some.path'; // mistyped the variable name
objectPath.set(obj, ok, 'some value'); 

/* ... */

$http.get('/endpoint').then(function(r) {
  if (objectPath.has(obj, r.path)) { // returns true even though r.path is undefined!
     return 'do something';
  }
  // it's actually in r.data.path, a return from angular $http, really easy to mess up
});

What is your opinion @mariocasciaro?
I think it's the only place where the module should actually forcefully throw, to prevent hard-to-debug scenarios, since it will 'swallow' the empty path. And we shouldn't worry about it in the next version, since it's a major breaking change anyway

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.