Skip to content

Commit

Permalink
feat(utils): listify, objectify
Browse files Browse the repository at this point in the history
Signed-off-by: Lexus Drumgold <[email protected]>
  • Loading branch information
unicornware committed Jul 21, 2023
1 parent a814536 commit d2c2018
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 0 deletions.
1 change: 1 addition & 0 deletions .dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ keyid
larsgw
lcov
lintstagedrc
listify
mkbuild
mlly
nocheck
Expand Down
11 changes: 11 additions & 0 deletions __fixtures__/vehicles-array.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* @file Test Fixtures - VEHICLES_ARRAY
* @module fixtures/VEHICLES_ARRAY
*/

import cast from '#src/utils/cast'
import values from '#src/utils/values'
import type Vehicle from './types/vehicle'
import VEHICLES_DICTIONARY from './vehicles-dictionary'

export default cast<readonly [Vehicle, Vehicle]>(values(VEHICLES_DICTIONARY))
21 changes: 21 additions & 0 deletions __fixtures__/vehicles-dictionary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* @file Test Fixtures - VEHICLES_DICTIONARY
* @module fixtures/VEHICLES_DICTIONARY
*/

import type Vehicle from './types/vehicle'

export default {
0: {
make: faker.vehicle.manufacturer(),
model: faker.vehicle.model(),
vin: faker.vehicle.vin(),
year: faker.date.past({ years: 3 }).getFullYear()
},
1: {
make: faker.vehicle.manufacturer(),
model: faker.vehicle.model(),
vin: faker.vehicle.vin(),
year: faker.date.past({ years: 5 }).getFullYear()
}
} as { [N in 0 | 1]: Vehicle }
18 changes: 18 additions & 0 deletions src/utils/__tests__/listify.spec-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @file Type Tests - listify
* @module tutils/utils/tests/unit-d/listify
*/

import type Vehicle from '#fixtures/types/vehicle'
import type testSubject from '../listify'

describe('unit-d:utils/listify', () => {
it('should return U[]', () => {
// Arrange
type T = readonly [Vehicle, Vehicle]
type U = Vehicle['vin']

// Expect
expectTypeOf<typeof testSubject<T, U>>().returns.toEqualTypeOf<U[]>()
})
})
20 changes: 20 additions & 0 deletions src/utils/__tests__/listify.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* @file Unit Tests - listify
* @module tutils/utils/tests/unit/listify
*/

import VEHICLES_DICTIONARY from '#fixtures/vehicles-dictionary'
import testSubject from '../listify'

describe('unit:utils/listify', () => {
it('should return obj as array', () => {
// Arrange
const obj: typeof VEHICLES_DICTIONARY = VEHICLES_DICTIONARY

// Act + Expect
expect(testSubject(obj, ([, vehicle]) => vehicle.vin)).to.deep.equal([
obj[0].vin,
obj[1].vin
])
})
})
20 changes: 20 additions & 0 deletions src/utils/__tests__/objectify.spec-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* @file Type Tests - objectify
* @module tutils/utils/tests/unit-d/objectify
*/

import type Vehicle from '#fixtures/types/vehicle'
import type testSubject from '../objectify'

describe('unit-d:utils/objectify', () => {
it('should return { [H in K]?: V }', () => {
// Arrange
type T = readonly [Vehicle, Vehicle]
type K = number
type V = Vehicle
type Expect = { [H in K]?: V }

// Expect
expectTypeOf<typeof testSubject<T, K, V>>().returns.toEqualTypeOf<Expect>()
})
})
19 changes: 19 additions & 0 deletions src/utils/__tests__/objectify.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* @file Unit Tests - objectify
* @module tutils/utils/tests/unit/objectify
*/

import VEHICLES_ARRAY from '#fixtures/vehicles-array'
import VEHICLES_DICTIONARY from '#fixtures/vehicles-dictionary'
import isObjectPlain from '../is-object-plain'
import testSubject from '../objectify'

describe('unit:utils/objectify', () => {
it('should return arr as plain object', () => {
// Act
const result = testSubject(VEHICLES_ARRAY)

// Expect
expect(result).to.eql(VEHICLES_DICTIONARY).and.satisfy(isObjectPlain)
})
})
2 changes: 2 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,10 @@ export { default as isWeakSet } from './is-weak-set'
export { default as join } from './join'
export { default as keys } from './keys'
export type { default as KeysOptions } from './keys.options'
export { default as listify } from './listify'
export { default as lowercase } from './lowercase'
export { default as noop } from './noop'
export { default as objectify } from './objectify'
export { default as overwrite } from './overwrite'
export {
default as overwriteWith,
Expand Down
36 changes: 36 additions & 0 deletions src/utils/listify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* @file Utilities - listify
* @module tutils/utils/listify
*/

import type { Entries, Mapper, Nilable } from '#src/types'
import entries from './entries'
import select from './select'

/**
* Converts an object to an array.
*
* @see {@linkcode Mapper}
*
* @template T - Object to convert
* @template U - Array item type
*
* @param {T} obj - Object to convert
* @param {Mapper<Entries<T>, U>} mapper - Object entry interpolator
* @return {U[]} New array
*/
const listify = <T extends Nilable<object>, U>(
obj: T,
mapper: Mapper<Entries<T>, U>
): U[] => {
/**
* Own enumerable string-keyed property key-value pairs of {@linkcode obj}.
*
* @const {Entries<T>} pairs
*/
const pairs: Entries<T> = entries(obj)

return select(pairs, null, (entry, i) => mapper(entry, i, pairs))
}

export default listify
40 changes: 40 additions & 0 deletions src/utils/objectify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* @file Utilities - objectify
* @module tutils/utils/objectify
*/

import type { Mapper, PropertyKey } from '#src/types'
import cast from './cast'
import define from './define'

/**
* Converts an array to a plain object.
*
* @see {@linkcode Mapper}
*
* @todo examples
*
* @template T - Array to convert
* @template K - Object key type
* @template V - Object value type
*
* @param {T} arr - Array to convert
* @param {Mapper<T, K>} [key=(_,index)=>index] - Object key function
* @param {Mapper<T, V>} [value=item=>item] - Object value function
* @return {Partial<Record<K, V>>} New plain object
*/
const objectify = <
T extends readonly unknown[],
K extends PropertyKey = number,
V = T[number]
>(
arr: T,
key: Mapper<T, K> = (_, index) => cast(index),
value: Mapper<T, V> = item => cast(item)
): { [H in K]?: V } => {
return arr.reduce<{ [H in K]?: V }>((acc, item, i) => {
return define(acc, key(item, i, arr), { value: value(item, i, arr) })
}, {})
}

export default objectify

0 comments on commit d2c2018

Please sign in to comment.