Skip to content

Commit 61e2436

Browse files
committed
Fix preserving leading underscores and dollar signs
Fixes #80
1 parent 77641b0 commit 61e2436

File tree

3 files changed

+71
-4
lines changed

3 files changed

+71
-4
lines changed

index.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,16 @@ const transform = (input, options = {}, isSeen = new WeakMap(), parentPath) => {
9393
if (cache.has(cacheKey)) {
9494
key = cache.get(cacheKey);
9595
} else {
96-
const returnValue = camelCase(key, {pascalCase, locale: false, preserveConsecutiveUppercase});
96+
// Preserve leading `_` and `$` as they typically have semantic meaning
97+
// This should eventually be fixed in the `camelcase` package itself
98+
const leadingPrefix = key.match(/^[_$]*/)[0];
99+
const transformed = camelCase(key.slice(leadingPrefix.length), {pascalCase, locale: false, preserveConsecutiveUppercase});
100+
key = leadingPrefix + transformed;
97101

98102
// Only cache reasonable length keys to prevent memory abuse
99103
if (key.length < 100) {
100-
cache.set(cacheKey, returnValue);
104+
cache.set(cacheKey, key);
101105
}
102-
103-
key = returnValue;
104106
}
105107
}
106108

readme.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ camelcaseKeys(commandLineArguments);
3333
//=> {_: [], fooBar: true}
3434
```
3535

36+
Leading `_` and `$` are preserved as they have semantic meaning.
37+
38+
```js
39+
camelcaseKeys({_foo_bar: true, $baz_qux: true});
40+
//=> {_fooBar: true, $bazQux: true}
41+
```
42+
3643
## API
3744

3845
### camelcaseKeys(input, options?)

test.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,64 @@ test('preserve numeric string keys', t => {
378378
t.deepEqual(camelcaseKeys([{'4.2': 'foo'}, {42: 'bar'}]), [{'4.2': 'foo'}, {42: 'bar'}]);
379379
});
380380

381+
test('preserve leading underscores and dollar signs', t => {
382+
// Single leading underscore
383+
t.deepEqual(camelcaseKeys({_name: true}), {_name: true});
384+
// eslint-disable-next-line camelcase
385+
t.deepEqual(camelcaseKeys({_name_obj: 'value'}), {_nameObj: 'value'});
386+
// eslint-disable-next-line camelcase
387+
t.deepEqual(camelcaseKeys({_foo_bar: true}), {_fooBar: true});
388+
389+
// Single leading dollar sign
390+
// eslint-disable-next-line camelcase
391+
t.deepEqual(camelcaseKeys({$foo_bar: true}), {$fooBar: true});
392+
t.deepEqual(camelcaseKeys({$element: true}), {$element: true});
393+
394+
// Multiple leading underscores
395+
// eslint-disable-next-line camelcase
396+
t.deepEqual(camelcaseKeys({__foo_bar: 'value'}), {__fooBar: 'value'});
397+
// eslint-disable-next-line camelcase
398+
t.deepEqual(camelcaseKeys({___foo_bar: 'value'}), {___fooBar: 'value'});
399+
400+
// Multiple leading dollar signs
401+
// eslint-disable-next-line camelcase
402+
t.deepEqual(camelcaseKeys({$$foo_bar: 'value'}), {$$fooBar: 'value'});
403+
404+
// Mixed leading characters
405+
// eslint-disable-next-line camelcase
406+
t.deepEqual(camelcaseKeys({$_foo_bar: 'value'}), {$_fooBar: 'value'});
407+
// eslint-disable-next-line camelcase
408+
t.deepEqual(camelcaseKeys({_$foo_bar: 'value'}), {_$fooBar: 'value'});
409+
// eslint-disable-next-line camelcase
410+
t.deepEqual(camelcaseKeys({__$foo_bar: 'value'}), {__$fooBar: 'value'});
411+
412+
// With pascalCase option
413+
// eslint-disable-next-line camelcase
414+
t.deepEqual(camelcaseKeys({_foo_bar: true}, {pascalCase: true}), {_FooBar: true});
415+
// eslint-disable-next-line camelcase
416+
t.deepEqual(camelcaseKeys({$foo_bar: true}, {pascalCase: true}), {$FooBar: true});
417+
418+
// With deep option
419+
t.deepEqual(
420+
// eslint-disable-next-line camelcase
421+
camelcaseKeys({_outer_key: {$inner_key: 'value'}}, {deep: true}),
422+
{_outerKey: {$innerKey: 'value'}},
423+
);
424+
425+
// In arrays
426+
t.deepEqual(
427+
// eslint-disable-next-line camelcase
428+
camelcaseKeys([{_foo_bar: true}, {$bar_foo: false}]),
429+
[{_fooBar: true}, {$barFoo: false}],
430+
);
431+
432+
// With preserveConsecutiveUppercase option
433+
// eslint-disable-next-line camelcase
434+
t.deepEqual(camelcaseKeys({_foo_BAR: true}, {preserveConsecutiveUppercase: true}), {_fooBAR: true});
435+
// eslint-disable-next-line camelcase
436+
t.deepEqual(camelcaseKeys({$foo_BAR: true}, {preserveConsecutiveUppercase: true}), {$fooBAR: true});
437+
});
438+
381439
/**
382440
Executes the library with the given arguments and resolves with the parsed result.
383441

0 commit comments

Comments
 (0)