Skip to content

Commit

Permalink
Add escapePath() (#90)
Browse files Browse the repository at this point in the history
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
  • Loading branch information
Richienb and sindresorhus committed Jan 22, 2022
1 parent a57d9fd commit 0505e98
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 1 deletion.
23 changes: 23 additions & 0 deletions index.d.ts
Expand Up @@ -108,3 +108,26 @@ console.log(object);
```
*/
export function deleteProperty(object: Record<string, any>, path: string): boolean;

/**
Escape special characters in a path. Useful for sanitizing user input.
@param path - The dot path to sanitize.
@example
```
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!'
```
*/
export function escapePath(path: string): string;
8 changes: 8 additions & 0 deletions index.js
Expand Up @@ -278,3 +278,11 @@ export function hasProperty(object, path) {

return true;
}

export function escapePath(path) {
if (typeof path !== 'string') {
throw new TypeError('Expected a string');
}

return path.replace(/[\\.[]/g, '\\$&');
}
19 changes: 19 additions & 0 deletions readme.md
Expand Up @@ -89,6 +89,25 @@ 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.

```js
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!'
```

#### object

Type: `object | array`
Expand Down
21 changes: 20 additions & 1 deletion test.js
@@ -1,5 +1,5 @@
import test from 'ava';
import {getProperty, setProperty, hasProperty, deleteProperty} from './index.js';
import {getProperty, setProperty, hasProperty, deleteProperty, escapePath} from './index.js';

test('getProperty', t => {
const fixture1 = {foo: {bar: 1}};
Expand Down Expand Up @@ -383,6 +383,25 @@ test('hasProperty', t => {
}, 'foo[0].bar.1'));
});

test('escapePath', t => {
t.is(escapePath('foo.bar[0]'), 'foo\\.bar\\[0]');
t.is(escapePath('foo\\.bar[0]'), 'foo\\\\\\.bar\\[0]');
t.is(escapePath('foo\\\.bar[0]'), 'foo\\\\\\.bar\\[0]'); // eslint-disable-line no-useless-escape
t.is(escapePath('foo\\\\.bar[0]'), 'foo\\\\\\\\\\.bar\\[0]');
t.is(escapePath('foo\\\\.bar\\\\[0]'), 'foo\\\\\\\\\\.bar\\\\\\\\\\[0]');
t.is(escapePath('foo[0].bar'), 'foo\\[0]\\.bar');
t.is(escapePath('foo.bar[0].baz'), 'foo\\.bar\\[0]\\.baz');
t.is(escapePath('[0].foo'), '\\[0]\\.foo');
t.is(escapePath(''), '');

t.throws(() => {
escapePath(0);
}, {
instanceOf: TypeError,
message: 'Expected a string',
});
});

test('prevent setting/getting `__proto__`', t => {
setProperty({}, '__proto__.unicorn', '🦄');
t.not({}.unicorn, '🦄'); // eslint-disable-line no-use-extend-native/no-use-extend-native
Expand Down

0 comments on commit 0505e98

Please sign in to comment.