Skip to content

Commit 0505e98

Browse files
Richienbsindresorhus
andauthoredJan 22, 2022
Add escapePath() (#90)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
1 parent a57d9fd commit 0505e98

File tree

4 files changed

+70
-1
lines changed

4 files changed

+70
-1
lines changed
 

‎index.d.ts

+23
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,26 @@ console.log(object);
108108
```
109109
*/
110110
export function deleteProperty(object: Record<string, any>, path: string): boolean;
111+
112+
/**
113+
Escape special characters in a path. Useful for sanitizing user input.
114+
115+
@param path - The dot path to sanitize.
116+
117+
@example
118+
```
119+
import {getProperty, escapePath} from 'dot-prop';
120+
121+
const object = {
122+
foo: {
123+
bar: '👸🏻 You found me Mario!',
124+
},
125+
'foo.bar' : '🍄 The princess is in another castle!',
126+
};
127+
const escapedPath = escapePath('foo.bar');
128+
129+
console.log(getProperty(object, escapedPath));
130+
//=> '🍄 The princess is in another castle!'
131+
```
132+
*/
133+
export function escapePath(path: string): string;

‎index.js

+8
Original file line numberDiff line numberDiff line change
@@ -278,3 +278,11 @@ export function hasProperty(object, path) {
278278

279279
return true;
280280
}
281+
282+
export function escapePath(path) {
283+
if (typeof path !== 'string') {
284+
throw new TypeError('Expected a string');
285+
}
286+
287+
return path.replace(/[\\.[]/g, '\\$&');
288+
}

‎readme.md

+19
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,25 @@ Delete the property at the given path.
8989

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

92+
### escapePath(path)
93+
94+
Escape special characters in a path. Useful for sanitizing user input.
95+
96+
```js
97+
import {getProperty, escapePath} from 'dot-prop';
98+
99+
const object = {
100+
foo: {
101+
bar: '👸🏻 You found me Mario!',
102+
},
103+
'foo.bar' : '🍄 The princess is in another castle!',
104+
};
105+
const escapedPath = escapePath('foo.bar');
106+
107+
console.log(getProperty(object, escapedPath));
108+
//=> '🍄 The princess is in another castle!'
109+
```
110+
92111
#### object
93112

94113
Type: `object | array`

‎test.js

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import test from 'ava';
2-
import {getProperty, setProperty, hasProperty, deleteProperty} from './index.js';
2+
import {getProperty, setProperty, hasProperty, deleteProperty, escapePath} from './index.js';
33

44
test('getProperty', t => {
55
const fixture1 = {foo: {bar: 1}};
@@ -383,6 +383,25 @@ test('hasProperty', t => {
383383
}, 'foo[0].bar.1'));
384384
});
385385

386+
test('escapePath', t => {
387+
t.is(escapePath('foo.bar[0]'), 'foo\\.bar\\[0]');
388+
t.is(escapePath('foo\\.bar[0]'), 'foo\\\\\\.bar\\[0]');
389+
t.is(escapePath('foo\\\.bar[0]'), 'foo\\\\\\.bar\\[0]'); // eslint-disable-line no-useless-escape
390+
t.is(escapePath('foo\\\\.bar[0]'), 'foo\\\\\\\\\\.bar\\[0]');
391+
t.is(escapePath('foo\\\\.bar\\\\[0]'), 'foo\\\\\\\\\\.bar\\\\\\\\\\[0]');
392+
t.is(escapePath('foo[0].bar'), 'foo\\[0]\\.bar');
393+
t.is(escapePath('foo.bar[0].baz'), 'foo\\.bar\\[0]\\.baz');
394+
t.is(escapePath('[0].foo'), '\\[0]\\.foo');
395+
t.is(escapePath(''), '');
396+
397+
t.throws(() => {
398+
escapePath(0);
399+
}, {
400+
instanceOf: TypeError,
401+
message: 'Expected a string',
402+
});
403+
});
404+
386405
test('prevent setting/getting `__proto__`', t => {
387406
setProperty({}, '__proto__.unicorn', '🦄');
388407
t.not({}.unicorn, '🦄'); // eslint-disable-line no-use-extend-native/no-use-extend-native

0 commit comments

Comments
 (0)