sindresorhus / dot-prop Goto Github PK
View Code? Open in Web Editor NEWGet, set, or delete a property from a nested object using a dot path
License: MIT License
Get, set, or delete a property from a nested object using a dot path
License: MIT License
const obj = {
a: [
{ b: 'cool' }
]
}
const r = dotProp.get(obj, 'a.0.nonexistant', 'bleep')
expected: r === 'bleep'
actual: r === undefined
Like how .set()
returns the result after setting a property, .delete()
should do the same.
Consider the following API:
import dotProp from 'dot-prop';
const object = {};
const view = dotProp(object);
view['foo.bar'] = 1;
console.log(object.foo.bar);
//=> 1
console.log(view['foo.bar']);
//=> 1
console.log('foo.bar' in view);
//=> true
delete view['foo.bar']
console.log('foo.bar' in view);
//=> false
Fully possible using Proxy
The issue is described on this SO post
This commit is the culprit apparently
Seems weird to me that this library throws on things like: null
, false
, 3
, "hi"
.
I feel like the obj === undefined
check should be isObj(obj)
or something.
So, today dependabot alerts squawked at me with a huge Vulnerability alert
ref: https://nvd.nist.gov/vuln/detail/CVE-2020-8116
just letting you know :)
Documentation:
const object = { foo: { bar: 'b', baz: 'x' } };
setProperty(object, 'foo.biz.0', 'a');
console.log(object);
//=> {foo: {bar: 'b', baz: 'x', biz: ['a']}}
Actual:
const object = { foo: { bar: 'b', baz: 'x' } };
setProperty(object, 'foo.biz.0', 'a');
console.log(object);
//=> {"foo": {"bar": "b", "baz": "x", "biz": { "0": "a" } }}
Also the following results in a exception:
const object = { foo: { bar: 'b', baz: 'x', biz: [] } };
setProperty(object, 'foo.biz.0', 'a');
console.log(object);
core.js:6498 ERROR Error: Cannot use string index
at assertNotStringIndex (index.js:169:1)
at setProperty (index.js:220:1)
Based on the severity of CVE-2020-8116 and the fact that 4.x is still very commonly used as a dependency, I would like to kindly request for the fix to be backported to 4.x and released as (presumably) v4.2.1.
Would this be possible? Many thanks in advance.
deepKeys({ x: 1, y: "1", z: [1], zz: [], o: {}, n: null, u: undefined, nan: NaN })
returns
['x', 'y', 'z[0]', 'n', 'u', 'nan']
Why is it missing zz
and o
, for me it is looks as bug
Hi! ๐
Firstly, thanks for your work on this project! ๐
Today I used patch-package to patch [email protected]
for the project I'm working on.
Here is the diff that solved my problem:
diff --git a/node_modules/dot-prop/index.js b/node_modules/dot-prop/index.js
index aa9c5bb..57a49b5 100644
--- a/node_modules/dot-prop/index.js
+++ b/node_modules/dot-prop/index.js
@@ -134,5 +134,9 @@ module.exports = {
}
return true;
+ },
+
+ escape(prop) {
+ return prop.replace(/\./g, '\\.')
}
};
This issue body was partially generated by patch-package.
"Expected" comes from the usage example in the readme and "Actual" comes from typescript's intellisense in VS Code.
The main thing I noticed is the setter and deleter don't seem to mutate the type.
I'm using v6.0.1
of dot-prop with typescript v4.2.4
.
import dotProp from 'dot-prop';
{
// Getter
dotProp.get({foo: {bar: 'unicorn'}}, 'foo.bar');
// Expected => 'unicorn'
// Actual => unknown
dotProp.get({foo: {bar: 'a'}}, 'foo.notDefined.deep');
// Expected => undefined
// Actual => unknown
dotProp.get({foo: {bar: 'a'}}, 'foo.notDefined.deep', 'default value');
// Expected => 'default value'
// Actual => 'default value'
dotProp.get({foo: {'dot.dot': 'unicorn'}}, 'foo.dot\\.dot');
// Expected => 'unicorn'
// Actual => unknown
}
{
// Setter
const object = {foo: {bar: 'a'}};
dotProp.set(object, 'foo.bar', 'b');
console.log(object);
// Expected => { foo: { bar: 'b' } }
// Actual => { foo: { bar: string; }; }
const foo = dotProp.set({}, 'foo.bar', 'c');
console.log(foo);
// Expected => {foo: {bar: 'c'}}
// Actual => const foo: {}
dotProp.set(object, 'foo.baz', 'x');
console.log(object);
// Expected => {foo: {bar: 'b', baz: 'x'}}
// Actual => const object: { foo: { bar: string; }; }
// Has
dotProp.has({foo: {bar: 'unicorn'}}, 'foo.bar');
// Expected => true
// Actual => boolean
}
{
// Deleter
const object = {foo: {bar: 'a'}};
dotProp.delete(object, 'foo.bar');
console.log(object);
// Expected => {foo: {}}
// Actual => const object: { foo: { bar: string; }; }
object.foo.bar = {x: 'y', y: 'x'};
// Type '{ x: string; y: string; }' is not assignable to type 'string'.ts(2322)
dotProp.delete(object, 'foo.bar.x');
console.log(object);
// Expected => {foo: {bar: {y: 'x'}}}
// Actual => const object: { foo: { bar: string; }; }
}
var a = {foo: undefined}
console.log(dotProp.has(a, 'foo')) // false
console.log('foo' in a) // true
console.log(a.hasOwnProperty('foo')) // true
deepKeys
should not return not existed keys
it("deepKeys should return correct values for sparsed arrays", () => {
// fixture setup
// eslint-disable-next-line no-sparse-arrays
const mockedData = [1, , 3];
const expectedState = Object.keys(mockedData).map(k => `[${k}]`);
const sut = () => deepKeys(mockedData);
// exercise system
const actualResult = sut();
// verify outcome
expect(actualResult).toEqual(expectedState);
});
- Expected - 0
+ Received + 1
Array [
"[0]",
+ "[1]",
"[2]",
]Jest
related to #108
Right now dot-prop will return any property that isn't undefined
. But as a potentially unintended consequence stuff like m.get({}, 'hasOwnProperty')
will return the non-enumerable method.
Instead of checking just for undefined
, maybe it should test obj.hasOwnProperty(prop)
.
I am just wondering about the differences between your package functions and the .get and .set functions of lodash. At a first glance it looks pretty much the same but I may have oberlooked something. Clarifying this might also help other users investigating your package. Note, lodash is also available as per-method packages. So it is possible to just to require lodash.get and lodash.set if one does not need the other 200 utility functions.
0 info it worked if it ends with ok
1 verbose cli [ '/usr/local/bin/node',
1 verbose cli '/usr/local/bin/npm',
1 verbose cli 'install',
1 verbose cli 'dot-prop' ]
2 info using [email protected]
3 info using [email protected]
4 verbose npm-session b440cea1dce7a2a9
5 silly install loadCurrentTree
6 silly install readLocalPackageData
7 http fetch GET 200 https://registry.npmjs.org/dot-prop 20ms (from cache)
8 silly fetchPackageMetaData error for dot-prop@latest Unexpected end of JSON input while parsing near '...d3a038bbee7bba865bdc7'
9 timing stage:rollbackFailedOptional Completed in 1ms
10 timing stage:runTopLevelLifecycles Completed in 72ms
11 verbose stack SyntaxError: Unexpected end of JSON input while parsing near '...d3a038bbee7bba865bdc7'
11 verbose stack at JSON.parse ()
11 verbose stack at parseJson (/usr/local/lib/node_modules/npm/node_modules/json-parse-better-errors/index.js:7:17)
11 verbose stack at consumeBody.call.then.buffer (/usr/local/lib/node_modules/npm/node_modules/node-fetch-npm/src/body.js:96:50)
11 verbose stack at process._tickCallback (internal/process/next_tick.js:68:7)
13 verbose Darwin 18.2.0
14 verbose argv "/usr/local/bin/node" "/usr/local/bin/npm" "install" "dot-prop"
15 verbose node v10.15.3
16 verbose npm v6.9.0
Not sure if this is the right forum for this but the old and insecure version of dot-prop 4.2.0 is still being installed in nodejs causing some security issues. Trying to update it does not work due to some dependencies. Who should I contact about this? I opened an issue here also but no clue how to deal with these types of issues: nodesource/distributions#1096
I ran into this issue when upgrading from 4->6, which of course is a breaking change, but I think the new behavior is inconsistent. ๐
Consider some objects that have arrays, like:
const emptyArray = { foo: [] }
const oneItem = { foo: [ { fizz: 'buzz' } ] }
I want to access properties on the array's objects, and provide a default value if it doesn't exist.
// passes: default value is found
t.is(dotProp.get(emptyArray, 'foo.0.fizz', 'bazz'), 'bazz')
// passes: existing value is found
t.is(dotProp.get(oneItem, 'foo.0.fizz', 'bazz'), 'buzz')
However, in 4->6 the behavior changed when accessing an array index that doesn't exist:
// passes in 4 but fails in 6
t.is(dotProp.get({ foo: [ 'bar' ] }, 'foo.1', 'bazz'), 'bazz')
// passes in 6 but fails in 4
t.is(dotProp.get({ foo: [ 'bar' ] }, 'foo.1', 'bazz'), undefined)
I think that this behavior is ... inconsistent, probably?
If accessing a deeper property in an array element triggers a default value fallback, shouldn't accessing an array element trigger a fallback if that index doesn't exist?
Hi @sindresorhus!
This module is pretty popular, and its functionality is fairly segmented (get vs set). I'm willing to bet a decent number of people are only using this to safely retrieve the value at a dotted path (not set).
Given that assumption, I was wondering if you'd be open to providing a JS Modules version where { set, get }
are named exports? I'd be happy to open a PR, though I'd need to know what solution you'd prefer for transpiling modules to commonjs (I'm biased).
Cheers!
Hi, I'm having some issues getting an object property with dot-prop and I'm not sure why it's not working. Here's the code:
const dotProp = require('dot-prop')
const lodashGet = require('lodash.get')
const mainDiv = document.createElement('div')
mainDiv.setAttribute('id', 'main')
document.body.appendChild(mainDiv)
const mainElem = document.querySelector('#main')
const testerObj = {
foo: 'bar'
}
console.log(dotProp.get(testerObj, 'foo'))
console.log(lodashGet(testerObj, 'foo'))
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
console.log(mutation)
console.log(dotProp.get(mutation, 'addedNodes'))
console.log(lodashGet(mutation, 'addedNodes'))
})
})
observer.observe(
mainElem,
{
childList: true,
subtree: true,
attributes: false,
characterData: false,
attributeOldValue: false,
characterDataOldValue: false
}
)
const newP = document.createElement('p')
mainElem.appendChild(newP)
I get the following output on the console:
bar
bar
MutationRecord { type: "childList", target: <div#main>, addedNodes: NodeList[1], removedNodes: NodeList[0], previousSibling: null, nextSibling: null, attributeName: null, attributeNamespace: null, oldValue: null }
undefined
NodeList [ <p> ]
If you want an easy way to try the code above, copy and paste it into https://esnextb.in/ and open the browser console to see the output.
Cheers.
This repo seems to be published without transpiling source-code.
This causes a painful issue with production facing applications that uglify their code since uglify doesn't work with ES6 yet.
I was able to get around the bug by transpiling this dependency with webpack before uglifying. But ideally, I think it's always better to do the transformation before publishing.
As @ruyadorno pointed out in Issue #63, there doesn't appear to be a tag for the specific set of code used to create version 4.2.1 of the dot-prop npm package. That issue has now been closed, so I'm creating this issue to track the remaining small task.
(Of course, it would be really nice if npm/Microsoft performed automated checks on whether a given npm package is verified so that an npm audit
would flag this).
delete
is an operator in javascript and thus is a reserved keyword. That means that you can't have a variable named delete
in any scope.
This also makes this module incompatible with rollup-plugin-commonjs since you cannot have exports named delete
.
I understand if you don't want to make this change, but I think it would be nice to rename the function to e.g. del
. This would make the module ready for ES6 Modules ๐
dotProp.has({foo: null}, 'foo.bar') // TypeError: Cannot read property 'bar' of null
dotProp.get({foo: 1}, 'foo.bar') // ( in node v0.12.2 ) TypeError: Object.getOwnPropertyDescriptor called on non-object
dotProp.delete({foo: null}, 'foo.bar') // Cannot convert undefined or null to object
This change was made in July 2016:
use `object.prototype.propertyIsEnumerable instead of `Object.getOwnPropertyDescriptor`
Unfortunately, this change broke my code. Specifically, I was using it like this in the Express framework:
dot = require( "dot-prop" );
req.app.locals.foo = 1;
console.log( "foo = " + dot.get( req, "app.locals.foo" ) );
where the req
object is defined here.
Before this change, foo = 1
was logged.
After this change, foo = undefined
was logged.
The problem appears to be that req.app
isn't an enumerable property because it is an inherited property.
So, here's my question: why are we discriminating against inherited properties inside the get()
method? That doesn't seem right to me.
is it possible to add dot notation to arrays fields - set\get\has
now it works like this: getProperty(obj, 'arr_field[1]')
expected: getProperty(obj, 'arr_field.1')
It should work since array is just an object and it's easier to connect code with other libraries
Trying to do something like this:
const dotProp = require('dot-prop')
const data = {
data: [{ price: 1234 }],
}
const result = dotProp.get(data, 'data[0].price')
But result is always undefined
Is this possible with this library? Or perhaps I should look at an alternative?
Hello,
first thanks for this library which was especially helpful for merging objects. :-)
The issue I have is with IE11 which does not seem to like the name of some functions like get
in get(obj, path, value)
and generate the classic error:
SCRIPT 1028 Expected identifier, string or number
Yet I'm using a whole bunch of transpilation tools to be sure the generated code is compatible with older browsers:
browserify --extension=.jsx --transform [babelify --presets=es2015,stage-2,react --plugins=[babel-plugin-transform-es3-member-expression-literals,babel-plugin-transform-es3-property-literals]] --transform [es3ify] GUI/index.jsx --outfile dist/GUI/bundle.js
But as far as I understand the tools consider your code as valid, which it is for most browsers indeed.
Have you ever heard about this issue?
Thanks.
Mickael
I do not know if this is something that you are after since this node version (4.2.6) is no longer officially supported but the 4.2.1
release breaks the package with this error:
TypeError: disallowedKeys.includes is not a function
at Array.some (native)
at pathSegments.some (/usr/src/app/node_modules/dot-prop/index.js:10:51)
at Object.get (/usr/src/app/node_modules/dot-prop/index.js:40:19)
at UpdateNotifier.check (/usr/src/app/node_modules/update-notifier/index.js:78:16)
at __dirname.check.checkNpm.then.checkNpm.module.exports.options (/usr/src/app/node_modules/update-notifier/index.js:151:17)
at Object.<anonymous> (/usr/src/app/node_modules/nodemon/bin/nodemon.js:15:29)
The issue comes from this 3039c8c#diff-168726dbe96b3ce427e7fedce31bb0bcR10
It is kind of a bummer sincenodemon
defines its dependency to this package as '^...' through update-notifier
which will automatically pick the latest minor version which is 4.2.1
4.2.0
works fine.
'foo.dot\\.dot'
could be optionally written as ['foo', 'dot', '.dot']
dotProp.get({foo: [{bar: 'unicorn'}]}, 'foo[0].bar'); // does this work?
We cannot currently use this in our codebase, as we don't run node_modules
through Babel, and we must target older browsers. let
and const
don't work for us.
Can this be transpiled before being published to NPM?
See https://snyk.io/test/npm/dot-prop/4.2.0
Thank you
Why don't you add a tutorial on what is dot prop and how to work with it.
Also i need to distinguish between an array and a dot prop.
I am just some beginner so don't expect to much.
After using dotProp.delete()
to remove an item from an array of objects, I'm finding that the array length stays the same. Shouldn't the count automatically update when an item is deleted? If not, how can I work around it to get the right length?
0: (...)
1: Object
children: Array(1)
0:
children: Array(2)
0: {__ob__: Observer}
length: 2
I think that it would be a good case when dotProp.get()
returns defualt value even when given object is not an instance of Object
.
Quick example:
var fields = undefined;
dotProp.get(fields, 'attributes.required', false);
// false
Right now it returns the passed object.
If you don't, can I PR?
๐
deepKeys doesn't work with sparsed arrays
it("deepKeys should not cause an error with sparsed arrays", () => {
// fixture setup
const mockedEntity = {
// eslint-disable-next-line no-sparse-arrays
open_hours: [1, , 3],
};
const sut = () => {
deepKeys(mockedEntity);
};
// exercise system
// verify outcome
expect(sut).not.toThrow();
});
Error name: "TypeError"
Error message: ".for is not iterable"
Hi, I've implemented this a couple of times but wondered whether there'd be any interest in including it in this library:
const obj = { foo: { bar: 1, baz: { 'a.b': 2 } } }
deepKeys(obj) // ['foo.bar', 'foo.baz.a\\.b']
Worth doing here because the \\.
is a convention invented by dot-prop (as far as I'm aware), so it makes sense for deepKeys
to return paths that getProperty
will later understand.
how to access a property like 'a\\b'
?
these getter tests fail:
t.is(m.get({'\\': true}, '\\\\'), true);
t.is(m.get({'a\\b': true}, 'a\\\\b'), true);
t.is(m.get({'fo\\.ob.az': {bar: true}}, 'fo\\\\\\.ob\\.az.bar'), true);
Is there a way to make it so setProperty
can merge, rather than replace?
Just for completeness. PR welcome :)
We could use the Get
type: https://github.com/sindresorhus/type-fest/blob/main/ts41/get.d.ts
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.