GithubHelp home page GithubHelp logo

sindresorhus / dot-prop Goto Github PK

View Code? Open in Web Editor NEW
789.0 14.0 66.0 96 KB

Get, set, or delete a property from a nested object using a dot path

License: MIT License

JavaScript 95.71% TypeScript 4.29%

dot-prop's Introduction

dot-prop

Get, set, or delete a property from a nested object using a dot path

Install

npm install dot-prop

Usage

import {getProperty, setProperty, hasProperty, deleteProperty} from 'dot-prop';

// Getter
getProperty({foo: {bar: 'unicorn'}}, 'foo.bar');
//=> 'unicorn'

getProperty({foo: {bar: 'a'}}, 'foo.notDefined.deep');
//=> undefined

getProperty({foo: {bar: 'a'}}, 'foo.notDefined.deep', 'default value');
//=> 'default value'

getProperty({foo: {'dot.dot': 'unicorn'}}, 'foo.dot\\.dot');
//=> 'unicorn'

getProperty({foo: [{bar: 'unicorn'}]}, 'foo[0].bar');
//=> 'unicorn'

// Setter
const object = {foo: {bar: 'a'}};
setProperty(object, 'foo.bar', 'b');
console.log(object);
//=> {foo: {bar: 'b'}}

const foo = setProperty({}, 'foo.bar', 'c');
console.log(foo);
//=> {foo: {bar: 'c'}}

setProperty(object, 'foo.baz', 'x');
console.log(object);
//=> {foo: {bar: 'b', baz: 'x'}}

setProperty(object, 'foo.biz[0]', 'a');
console.log(object);
//=> {foo: {bar: 'b', baz: 'x', biz: ['a']}}

// Has
hasProperty({foo: {bar: 'unicorn'}}, 'foo.bar');
//=> true

// Deleter
const object = {foo: {bar: 'a'}};
deleteProperty(object, 'foo.bar');
console.log(object);
//=> {foo: {}}

object.foo.bar = {x: 'y', y: 'x'};
deleteProperty(object, 'foo.bar.x');
console.log(object);
//=> {foo: {bar: {y: 'x'}}}

API

getProperty(object, path, defaultValue?)

Get the value of the property at the given path.

Returns the value if any.

setProperty(object, path, value)

Set the property at the given path to the given value.

Returns the object.

hasProperty(object, path)

Check whether the property at the given path exists.

Returns a boolean.

deleteProperty(object, path)

Delete the property at the given path.

Returns a boolean of whether the property existed before being deleted.

escapePath(path)

Escape special characters in a path. Useful for sanitizing user input.

import {getProperty, escapePath} from 'dot-prop';

const object = {
	foo: {
		bar: 'πŸ‘ΈπŸ» You found me Mario!',
	},
	'foo.bar' : 'πŸ„ The princess is in another castle!',
};
const escapedPath = escapePath('foo.bar');

console.log(getProperty(object, escapedPath));
//=> 'πŸ„ The princess is in another castle!'

deepKeys(object)

Returns an array of every path. Non-empty plain objects and arrays are deeply recursed and are not themselves included.

This can be useful to help flatten an object for an API that only accepts key-value pairs or for a tagged template literal.

import {getProperty, deepKeys} from 'dot-prop';

const user = {
	name: {
		first: 'Richie',
		last: 'Bendall',
	},
	activeTasks: [],
	currentProject: null
};

for (const property of deepKeys(user)) {
	console.log(`${property}: ${getProperty(user, property)}`);
	//=> name.first: Richie
	//=> name.last: Bendall
	//=> activeTasks: []
	//=> currentProject: null
}

Sparse arrays are supported. In general, avoid using sparse arrays.

object

Type: object | array

Object or array to get, set, or delete the path value.

You are allowed to pass in undefined as the object to the get and has functions.

path

Type: string

Path of the property in the object, using . to separate each nested key.

Use \\. if you have a . in the key.

The following path components are invalid and results in undefined being returned: __proto__, prototype, constructor.

value

Type: unknown

Value to set at path.

defaultValue

Type: unknown

Default value.

dot-prop's People

Contributors

authorproxy avatar bendingbender avatar bendrucker avatar coreyfarrell avatar floatdrop avatar jeremyruppel avatar jetfault avatar jimbly avatar johansteffner avatar kjellmorten avatar kphrx avatar linusu avatar manovotny avatar marcjansen avatar mmkal avatar radmen avatar rexxars avatar richienb avatar samverschueren avatar sindresorhus avatar stevemao avatar stroncium avatar thatjessicakelly avatar

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

dot-prop's Issues

Version 4.2.0 is default in nodejs

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

Provide built library

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?

support of backslashes in properties?

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);

Consider renaming delete

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 πŸš€

Too many bugs in this repo

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

How to access data with array

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?

Array length doesn't change after deleting item

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

Provide JS Modules export?

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!

Dot prop Wiki and Tutorial

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.

Error "SCRIPT 1028 Expected identifier, string or number" with IE11

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

Unexpected end of JSON input while parsing near '...d3a038bbee7bba865bdc7'

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

Create tag for version 4.2.1

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).

Support array index access

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?

deepKeys returns strange result

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

get() method's switch to object.prototype.propertyIsEnumerable broke my code

Issuehunt badges

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.


IssueHunt Summary

stroncium stroncium has been rewarded.

Backers (Total: $40.00)

Submitted pull Requests


Tips

Difference to lodash .set and .get?

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.

deepKeys doesn't work with sparsed arrays: ".for is not iterable"

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"

Array types not working as per documentation

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)

add possibility to use dot notation with arrays

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

Uglify issues with this repo

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.

`deepKeys` helper?

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.

Dot Prop Views

Consider this additional API:

import dotProp from 'dot-prop';

const object = {};
const objectDot = dotProp(object);

objectDot['foo.bar'] = 1;

console.log(object.foo.bar);
//=> 1

console.log(objectDot['foo.bar']);
//=> 1

console.log('foo.bar' in objectDot);
//=> true

delete objectDot['foo.bar']

console.log('foo.bar' in objectDot);
//=> false

Fully possible using Proxy

get() from undefined should return default value

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.

deepKeys works wrong for sparsed arrays

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

Breaks node4 compatability (4.2.6)

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.

hasOwnProperty

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).

escape()

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.

Possible issue with a MutationRecord object?

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.

Examples don't seem to have correct typescript types

"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; }; }
}

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.