Skip to content

Commit

Permalink
Add mapObject.mapObjectSkip for removing object keys (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
gr2m authored Sep 19, 2021
1 parent 6a10109 commit 9ee1876
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 3 deletions.
25 changes: 24 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ declare namespace mapObject {
targetKey: MappedObjectKeyType,
targetValue: MappedObjectValueType,
mapperOptions?: mapObject.MapperOptions
];
] | typeof mapObject.mapObjectSkip;

interface Options {
/**
Expand Down Expand Up @@ -45,8 +45,28 @@ declare namespace mapObject {
*/
shouldRecurse?: boolean;
}

/**
Return this value from a `mapper` function to remove a key from an object.
```js
const mapObject = require('map-obj');
const object = {one: 1, two: 2}
const mapper = (key, value) => value === 1 ? [key, value] : mapObject.mapObjectSkip
const result = mapObject(object, mapper);
console.log(result);
//=> {one: 1}
```
*/
const mapObjectSkip: typeof uniqueSymbol
}

// unique symbol cannot be declared in a namespace directly, so we declare it top-level
// See: https://github.com/sindresorhus/map-obj/pull/38#discussion_r702396878
declare const uniqueSymbol: unique symbol;

/**
Map object keys and values into a new object.
Expand All @@ -65,6 +85,9 @@ const newObject = mapObject({FOO: true, bAr: {bAz: true}}, (key, value) => [key.
const newObject = mapObject({FOO: true, bAr: {bAz: true}}, (key, value) => [key.toLowerCase(), value], {deep: true});
//=> {foo: true, bar: {baz: true}}
const newObject = mapObject({one: 1, two: 2}, (key, value) => value === 1 ? [key, value] : mapObject.mapObjectSkip);
//=> {one: 1}
```
*/
declare function mapObject<
Expand Down
11 changes: 10 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const isObject = value => typeof value === 'object' && value !== null;
const mapObjectSkip = Symbol('skip');

// Customized for this use-case
const isObjectCustom = value =>
Expand Down Expand Up @@ -31,7 +32,13 @@ const mapObject = (object, mapper, options, isSeen = new WeakMap()) => {
}

for (const [key, value] of Object.entries(object)) {
let [newKey, newValue, {shouldRecurse = true} = {}] = mapper(key, value, object);
const mapResult = mapper(key, value, object);

if (mapResult === mapObjectSkip) {
continue;
}

let [newKey, newValue, {shouldRecurse = true} = {}] = mapResult;

// Drop `__proto__` keys.
if (newKey === '__proto__') {
Expand All @@ -57,3 +64,5 @@ module.exports = (object, mapper, options) => {

return mapObject(object, mapper, options);
};

module.exports.mapObjectSkip = mapObjectSkip;
2 changes: 2 additions & 0 deletions index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ expectAssignable<{[key: string]: unknown}>(object3);
expectType<'baz'>(object3.bar);

mapObject({foo: 'bar'}, (key, value) => [value, key, {shouldRecurse: false}]);

mapObject({foo: 'bar'}, () => mapObject.mapObjectSkip);
20 changes: 19 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ const newObject = mapObject({FOO: true, bAr: {bAz: true}}, (key, value) => [key.

const newObject = mapObject({FOO: true, bAr: {bAz: true}}, (key, value) => [key.toLowerCase(), value], {deep: true});
//=> {foo: true, bar: {baz: true}}

const newObject = mapObject({one: 1, two: 2}, (key, value) => value === 1 ? [key, value] : mapObject.mapObjectSkip);
//=> {one: 1}
```

## API
Expand All @@ -35,7 +38,7 @@ Source object to copy properties from.

#### mapper

Type: `(sourceKey, sourceValue, source) => [targetKey, targetValue, mapperOptions?]`
Type: `(sourceKey, sourceValue, source) => [targetKey, targetValue, mapperOptions?] | mapObject.mapObjectSkip`

Mapping function.

Expand Down Expand Up @@ -66,6 +69,21 @@ Default: `{}`

Target object to map properties on to.

### mapObject.mapObjectSkip

Return this value from a `mapper` function to exclude the key from the new object.

```js
const mapObject = require('map-obj');

const object = {one: 1, two: 2}
const mapper = (key, value) => value === 1 ? [key, value] : mapObject.mapObjectSkip
const result = mapObject(object, mapper);

console.log(result);
//=> {one: 1}
```

## Related

- [filter-obj](https://github.com/sindresorhus/filter-obj) - Filter object keys and values into a new object
Expand Down
15 changes: 15 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,18 @@ test('__proto__ keys are safely dropped', t => {
// the prototype by identity
t.is(Object.getPrototypeOf(output), Object.prototype);
});

test('remove keys (#36)', t => {
const object = {
one: 1,
two: 2
};

const expected = {
one: 1
};

const mapper = (key, value) => value === 1 ? [key, value] : mapObject.mapObjectSkip;
const actual = mapObject(object, mapper, {deep: true});
t.deepEqual(actual, expected);
});

0 comments on commit 9ee1876

Please sign in to comment.