Skip to content

Commit

Permalink
feat: add toObjectWith
Browse files Browse the repository at this point in the history
`toObject` is also now implemented by using `toObjectWith` with an identity function.
  • Loading branch information
haltcase committed Jan 9, 2020
1 parent f86b9de commit 52459a3
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 22 deletions.
30 changes: 30 additions & 0 deletions src/to-object-with.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import reduce from './reduce'
import getType from './get-type'
import isPrimitive from './is-primitive'

export default function toObjectWith (value, fn) {
const fnType = getType(fn)
if (fnType !== 'function') {
throw new TypeError(`Expected a function, got ${fnType}`)
}

if (isPrimitive(value)) return { [value]: fn(value) }

let inputType = getType(value)
if (inputType === 'object') return value

if (inputType === 'map' || inputType === 'set') {
inputType = 'array'
value = Array.from(value)
}

if (inputType !== 'array') return {}

return reduce(value, (acc, key) => {
if (Array.isArray(key) && key.length === 2) {
return Object.assign(acc, { [key[0]]: fn(key[1]) })
}

return Object.assign(acc, { [key]: fn(key) })
}, {})
}
24 changes: 2 additions & 22 deletions src/to-object.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,5 @@
import reduce from './reduce'
import getType from './get-type'
import isPrimitive from './is-primitive'
import toObjectWith from './to-object-with'

export default function toObject (value) {
if (isPrimitive(value)) return { [value]: value }

let inputType = getType(value)
if (inputType === 'object') return value

if (inputType === 'map' || inputType === 'set') {
inputType = 'array'
value = Array.from(value)
}

if (inputType !== 'array') return {}

return reduce(value, (acc, key) => {
if (Array.isArray(key) && key.length === 2) {
return Object.assign(acc, { [key[0]]: key[1] })
}

return Object.assign(acc, { [key]: key })
}, {})
return toObjectWith(value, v => v)
}
76 changes: 76 additions & 0 deletions tests/to-object-with.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import test from 'ava'
import fn from '../prod/to-object-with'

const run = (expectedValues, input = expectedValues) => {
const results = []

const callback = value => {
results.push(expectedValues.includes(value))
return value
}

fn(input, callback)

return results.every(Boolean)
}

test('array: callback receives each element', t => {
t.true(run(['one', 'two', 'three']))
})

test('primitive: callback receives the primitive', t => {
t.true(run([3], 3))
t.true(run([true], true))
t.true(run(['fly'], 'fly'))
t.true(run([null], null))
t.true(run([undefined], undefined))
})

test('object: callback receives each value', t => {
t.true(run(['cool'], { ultra: 'cool' }))
})

test('array: callback receives value of object entry-like elements', t => {
const input = [['keyOne', 1], ['keyTwo', 2], ['keyThree', 3]]
t.true(run([1, 2, 3], input))
})

test('map: callback receives each element', t => {
const input = new Map([['keyOne', 1], ['keyTwo', 2], ['keyThree', 3]])
t.true(run([1, 2, 3], input))
})

test('set: callback receives each element', t => {
const input = new Set(['one', 'two', 'three'])
t.true(run(['one', 'two', 'three'], input))
})

test('returns an empty object for unhandled types', t => {
t.throws(() => fn('input'), TypeError)
})

test('allows for transforming values of the resulting object', t => {
const input = new Set(['one', 'two', 'three', 'four', 'five'])

const callback = value => {
switch (value) {
case 'one': return 1
case 'two': return 2
case 'three': return 3
case 'four': return 4
case 'five': return 5
}
}

const actual = fn(input, callback)

const expected = {
one: [1],
two: [2],
three: [3],
four: [4],
five: [5]
}

t.deepEqual(actual, expected)
})

0 comments on commit 52459a3

Please sign in to comment.