Skip to content

Commit

Permalink
add keys function to object module (#226)
Browse files Browse the repository at this point in the history
* add keys function to object module
  • Loading branch information
sodiray authored Jan 6, 2023
1 parent 7022f29 commit 3975ea5
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 32 deletions.
1 change: 1 addition & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Please provide a detailed description of the changes and the intent behind them
- [ ] Tests have 100% coverage
- [ ] If code changes were made, the version in `package.json` has been bumped (matching semver)
- [ ] If code changes were made, the `yarn build` command has been run and to update the `cdn` directory
- [ ] If code changes were made, the documentation (in the `/docs` directory) has been updated

## Resolves

Expand Down
44 changes: 30 additions & 14 deletions cdn/radash.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -557,8 +557,8 @@ const toInt = (value, defaultValue) => {
const shake = (obj, filter = (x) => x === void 0) => {
if (!obj)
return {};
const keys = Object.keys(obj);
return keys.reduce((acc, key) => {
const keys2 = Object.keys(obj);
return keys2.reduce((acc, key) => {
if (filter(obj[key])) {
return acc;
} else {
Expand All @@ -568,15 +568,15 @@ const shake = (obj, filter = (x) => x === void 0) => {
}, {});
};
const mapKeys = (obj, mapFunc) => {
const keys = Object.keys(obj);
return keys.reduce((acc, key) => {
const keys2 = Object.keys(obj);
return keys2.reduce((acc, key) => {
acc[mapFunc(key, obj[key])] = obj[key];
return acc;
}, {});
};
const mapValues = (obj, mapFunc) => {
const keys = Object.keys(obj);
return keys.reduce((acc, key) => {
const keys2 = Object.keys(obj);
return keys2.reduce((acc, key) => {
acc[key] = mapFunc(obj[key], key);
return acc;
}, {});
Expand All @@ -593,8 +593,8 @@ const mapEntries = (obj, toEntry) => {
const invert = (obj) => {
if (!obj)
return {};
const keys = Object.keys(obj);
return keys.reduce((acc, key) => {
const keys2 = Object.keys(obj);
return keys2.reduce((acc, key) => {
acc[obj[key]] = key;
return acc;
}, {});
Expand Down Expand Up @@ -625,21 +625,21 @@ const listify = (obj, toItem) => {
return acc;
}, []);
};
const pick = (obj, keys) => {
const pick = (obj, keys2) => {
if (!obj)
return {};
return keys.reduce((acc, key) => {
return keys2.reduce((acc, key) => {
if (obj.hasOwnProperty(key))
acc[key] = obj[key];
return acc;
}, {});
};
const omit = (obj, keys) => {
const omit = (obj, keys2) => {
if (!obj)
return {};
if (!keys || keys.length === 0)
if (!keys2 || keys2.length === 0)
return obj;
return keys.reduce(
return keys2.reduce(
(acc, key) => {
delete acc[key];
return acc;
Expand Down Expand Up @@ -681,6 +681,22 @@ const assign = (a, b) => {
};
}, {});
};
const keys = (value) => {
if (!value)
return [];
const getKeys = (nested, paths) => {
if (isObject(nested)) {
return Object.entries(nested).flatMap(
([k, v]) => getKeys(v, [...paths, k])
);
}
if (isArray(nested)) {
return nested.flatMap((item, i) => getKeys(item, [...paths, `${i}`]));
}
return [paths.join(".")];
};
return getKeys(value, []);
};

const random = (min, max) => {
return Math.floor(Math.random() * (max - min + 1) + min);
Expand Down Expand Up @@ -819,4 +835,4 @@ const trim = (str, charsToTrim = " ") => {
return str.replace(regex, "");
};

export { alphabetical, assign, boil, callable, camel, capitalize, chain, clone, cluster, compose, counting, dash, debounce, defer, diff, draw, first, flat, fork, get, group, intersects, invert, isArray, isDate, isEmpty, isEqual, isFloat, isFunction, isInt, isNumber, isObject, isPrimitive, isString, isSymbol, iterate, last, list, listify, lowerize, map, mapEntries, mapKeys, mapValues, max, memo, merge, min, objectify, omit, parallel, partial, partob, pascal, pick, proxied, random, range, reduce, replace, replaceOrAppend, retry, select, series, shake, shift, shuffle, sift, sleep, snake, sort, sum, template, throttle, title, toFloat, toInt, toggle, trim, tryit as try, tryit, uid, unique, upperize, zip, zipToObject };
export { alphabetical, assign, boil, callable, camel, capitalize, chain, clone, cluster, compose, counting, dash, debounce, defer, diff, draw, first, flat, fork, get, group, intersects, invert, isArray, isDate, isEmpty, isEqual, isFloat, isFunction, isInt, isNumber, isObject, isPrimitive, isString, isSymbol, iterate, keys, last, list, listify, lowerize, map, mapEntries, mapKeys, mapValues, max, memo, merge, min, objectify, omit, parallel, partial, partob, pascal, pick, proxied, random, range, reduce, replace, replaceOrAppend, retry, select, series, shake, shift, shuffle, sift, sleep, snake, sort, sum, template, throttle, title, toFloat, toInt, toggle, trim, tryit as try, tryit, uid, unique, upperize, zip, zipToObject };
43 changes: 30 additions & 13 deletions cdn/radash.js
Original file line number Diff line number Diff line change
Expand Up @@ -560,8 +560,8 @@ var radash = (function (exports) {
const shake = (obj, filter = (x) => x === void 0) => {
if (!obj)
return {};
const keys = Object.keys(obj);
return keys.reduce((acc, key) => {
const keys2 = Object.keys(obj);
return keys2.reduce((acc, key) => {
if (filter(obj[key])) {
return acc;
} else {
Expand All @@ -571,15 +571,15 @@ var radash = (function (exports) {
}, {});
};
const mapKeys = (obj, mapFunc) => {
const keys = Object.keys(obj);
return keys.reduce((acc, key) => {
const keys2 = Object.keys(obj);
return keys2.reduce((acc, key) => {
acc[mapFunc(key, obj[key])] = obj[key];
return acc;
}, {});
};
const mapValues = (obj, mapFunc) => {
const keys = Object.keys(obj);
return keys.reduce((acc, key) => {
const keys2 = Object.keys(obj);
return keys2.reduce((acc, key) => {
acc[key] = mapFunc(obj[key], key);
return acc;
}, {});
Expand All @@ -596,8 +596,8 @@ var radash = (function (exports) {
const invert = (obj) => {
if (!obj)
return {};
const keys = Object.keys(obj);
return keys.reduce((acc, key) => {
const keys2 = Object.keys(obj);
return keys2.reduce((acc, key) => {
acc[obj[key]] = key;
return acc;
}, {});
Expand Down Expand Up @@ -628,21 +628,21 @@ var radash = (function (exports) {
return acc;
}, []);
};
const pick = (obj, keys) => {
const pick = (obj, keys2) => {
if (!obj)
return {};
return keys.reduce((acc, key) => {
return keys2.reduce((acc, key) => {
if (obj.hasOwnProperty(key))
acc[key] = obj[key];
return acc;
}, {});
};
const omit = (obj, keys) => {
const omit = (obj, keys2) => {
if (!obj)
return {};
if (!keys || keys.length === 0)
if (!keys2 || keys2.length === 0)
return obj;
return keys.reduce(
return keys2.reduce(
(acc, key) => {
delete acc[key];
return acc;
Expand Down Expand Up @@ -684,6 +684,22 @@ var radash = (function (exports) {
};
}, {});
};
const keys = (value) => {
if (!value)
return [];
const getKeys = (nested, paths) => {
if (isObject(nested)) {
return Object.entries(nested).flatMap(
([k, v]) => getKeys(v, [...paths, k])
);
}
if (isArray(nested)) {
return nested.flatMap((item, i) => getKeys(item, [...paths, `${i}`]));
}
return [paths.join(".")];
};
return getKeys(value, []);
};

const random = (min, max) => {
return Math.floor(Math.random() * (max - min + 1) + min);
Expand Down Expand Up @@ -858,6 +874,7 @@ var radash = (function (exports) {
exports.isString = isString;
exports.isSymbol = isSymbol;
exports.iterate = iterate;
exports.keys = keys;
exports.last = last;
exports.list = list;
exports.listify = listify;
Expand Down
2 changes: 1 addition & 1 deletion cdn/radash.min.js

Large diffs are not rendered by default.

58 changes: 58 additions & 0 deletions docs/object/keys.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
title: keys
description: Get all keys from an object deeply
group: Object
---

## Basic usage

Given an object, return all of it's keys and children's keys deeply as a flat string list.

```ts
import { keys } from 'radash'

const ra = {
name: 'ra',
power: 100,
friend: {
name: 'loki',
power: 80
},
enemies: [
{
name: 'hathor',
power: 12
}
]
}

keys(ra)
// => [
// 'name',
// 'power',
// 'friend.name',
// 'friend.power',
// 'enemies.0.name',
// 'enemies.0.power'
// ]
```

This is a function you might like to use with `get`, which dynamically looks up values in an object given a string path. Using the two together you could do something like flatten a deep object.

```ts
import { keys, get, objectify } from 'radash'

objectify(
keys(ra),
key => key,
key => get(ra, key)
)
// => {
// 'name': 'ra'
// 'power': 100
// 'friend.name': 'loki'
// 'friend.power': 80
// 'enemies.0.name': 'hathor'
// 'enemies.0.power': 12
// }
```
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "radash",
"version": "10.3.2",
"version": "10.4.0",
"description": "Functional utility library - modern, simple, typed, powerful",
"main": "dist/cjs/index.cjs",
"module": "dist/esm/index.mjs",
Expand All @@ -27,8 +27,8 @@
"docs:install": "yarn && yarn add --dev next@12.3.4",
"docs:build": "chiller build --ci",
"lint": "tslint -p tsconfig.json",
"format": "prettier --write \"./**/*.ts\"",
"format:check": "prettier --check \"**/*.ts\" --ignore-unknown"
"format": "prettier --write \"src/**/*.ts\"",
"format:check": "prettier --check \"src/**/*.ts\" --ignore-unknown"
},
"devDependencies": {
"@rollup/plugin-typescript": "^10.0.1",
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export {
clone,
get,
invert,
keys,
listify,
lowerize,
mapEntries,
Expand Down
26 changes: 25 additions & 1 deletion src/object.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isObject, isPrimitive } from './typed'
import { isArray, isObject, isPrimitive } from './typed'

type LowercasedKeys<T extends Record<string, any>> = {
[P in keyof T & string as Lowercase<P>]: T[P]
Expand Down Expand Up @@ -245,3 +245,27 @@ export const assign = <X extends Record<string | symbol | number, any>>(
}
}, {} as X)
}

/**
* Get a string list of all key names that exist in
* an object (deep).
*
* @example
* keys({ name: 'ra' }) // ['name']
* keys({ name: 'ra', children: [{ name: 'hathor' }] }) // ['name', 'children.0.name']
*/
export const keys = <TValue extends object>(value: TValue): string[] => {
if (!value) return []
const getKeys = (nested: any, paths: string[]): string[] => {
if (isObject(nested)) {
return Object.entries(nested).flatMap(([k, v]) =>
getKeys(v, [...paths, k])
)
}
if (isArray(nested)) {
return nested.flatMap((item, i) => getKeys(item, [...paths, `${i}`]))
}
return [paths.join('.')]
}
return getKeys(value, [])
}
32 changes: 32 additions & 0 deletions src/tests/object.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,4 +383,36 @@ describe('object module', () => {
assert.deepEqual(result, b)
})
})

describe('keys function', () => {
test('handles bad input', () => {
assert.deepEqual(_.keys({}), [])
assert.deepEqual(_.keys(null as any), [])
assert.deepEqual(_.keys(undefined as any), [])
})
test('returns correct list of keys', () => {
const ra = {
name: 'ra',
power: 100,
friend: {
name: 'loki',
power: 80
},
enemies: [
{
name: 'hathor',
power: 12
}
]
}
assert.deepEqual(_.keys(ra), [
'name',
'power',
'friend.name',
'friend.power',
'enemies.0.name',
'enemies.0.power'
])
})
})
})

1 comment on commit 3975ea5

@vercel
Copy link

@vercel vercel bot commented on 3975ea5 Jan 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.