Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"combokeys": "^3.0.0",
"events": "^1.0.2",
"invariant": "^2.1.0",
"lodash": "^4.15.0",
"just-reduce-object": "^1.0.3",
"platform": "^1.3.0",
"prop-types": "^15.5.8"
},
Expand Down Expand Up @@ -69,6 +69,7 @@
"jsdom": "^8.0.4",
"less": "^2.5.1",
"less-loader": "^2.2.0",
"lodash": "^4.15.0",
"mocha": "^2.2.5",
"react": "^0.14.8 || ^15",
"react-addons-test-utils": "^0.14.8 || ^15",
Expand Down
25 changes: 11 additions & 14 deletions src/shortcut-manager.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import _ from 'lodash'
import reduce from 'just-reduce-object'
import invariant from 'invariant'
import { EventEmitter } from 'events'
import helpers from './helpers'
import { isPlainObject, findKey, isArray, map, compact, flatten } from './utils'


const warning = (text) => {
Expand Down Expand Up @@ -31,8 +32,8 @@ class ShortcutManager extends EventEmitter {
_platformName = helpers.getPlatformName()

_parseShortcutDescriptor = (item) => {
if (_.isPlainObject(item)) {
return _.get(item, this._platformName)
if (isPlainObject(item)) {
return item[this._platformName]
}
return item
}
Expand All @@ -57,8 +58,8 @@ class ShortcutManager extends EventEmitter {

getAllShortcutsForPlatform(platformName) {
const _transformShortcuts = (shortcuts) => {
return _.reduce(shortcuts, (result, keyValue, keyName) => {
if (_.isPlainObject(keyValue)) {
return reduce(shortcuts, (result, keyName, keyValue) => {
if (isPlainObject(keyValue)) {
if (keyValue[platformName]) {
keyValue = keyValue[platformName]
} else {
Expand Down Expand Up @@ -89,21 +90,17 @@ class ShortcutManager extends EventEmitter {
return
}

const shortcuts = _(cursor)
.map(this._parseShortcutDescriptor)
.flatten()
.compact()
.value()
const shortcuts = compact(flatten(map(cursor, this._parseShortcutDescriptor)))

return shortcuts
}

_parseShortcutKeyName(obj, keyName) {
const result = _.findKey(obj, (item) => {
if (_.isPlainObject(item)) {
item = _.get(item, this._platformName)
const result = findKey(obj, (item) => {
if (isPlainObject(item)) {
item = item[this._platformName]
}
if (_.isArray(item)) {
if (isArray(item)) {
const index = item.indexOf(keyName)
if (index >= 0) { item = item[index] }
}
Expand Down
49 changes: 49 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
export const isArray = arr => Array.isArray(arr)

export const isPlainObject = (obj) => {
const isObject = typeof obj === 'object' && obj !== null && !isArray(obj)
if (!isObject || (obj.toString && obj.toString() !== '[object Object]')) return false
const proto = Object.getPrototypeOf(obj)
if (proto === null) {
return true
}
const Ctor = Object.prototype.hasOwnProperty.call(proto, 'constructor') && proto.constructor
return typeof Ctor === 'function' && Ctor instanceof Ctor &&
Function.prototype.toString.call(Ctor) === Function.prototype.toString.call(Object)
}

export const findKey = (obj, fn) => {
if (!isPlainObject(obj) && !isArray(obj)) return

const keys = Object.keys(obj)
return keys.find(key => fn(obj[key]))
}

export const compact = arr => arr.filter(Boolean)

const flattenOnce = (arr, recurse = true) => {
return arr.reduce((acc, val) => {
if (isArray(val) && recurse) return acc.concat(flattenOnce(val, false))
acc.push(val)
return acc
}, [])
}

export const flatten = (arr) => {
if (!isArray(arr)) throw new Error('flatten expects an array')
return flattenOnce(arr)
}

export const map = (itr, fn) => {
if (isArray(itr)) return itr.map(fn)

const results = []
const keys = Object.keys(itr)
const len = keys.length
for (let i = 0; i < len; i += 1) {
const key = keys[i]
results.push(fn(itr[key], key))
}

return results
}
132 changes: 132 additions & 0 deletions test/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import chai from 'chai'
import _ from 'lodash'
import { isArray, isPlainObject, findKey, compact, flatten, map } from '../src/utils'

describe('utils', () => {
const { expect } = chai
let primitives

beforeEach(() => {
function fn() { this.a = 1 }

primitives = [
['array'],
{ object: true },
Object.create(null),
'string',
null,
undefined,
NaN,
new Map([[ 1, 'one' ], [ 2, 'two' ]]),
new fn(),
true,
42,
]
})

describe('isArray', () => {
it('should be true for arrays', () => {
primitives.forEach((val, idx) => {
if (idx === 0) {
expect(isArray(val)).to.be.true
expect(_.isArray(val)).to.be.true
} else {
expect(isArray(val)).to.be.false
expect(_.isArray(val)).to.be.false
}
})
})
})

describe('isPlainObject', () => {
it('should be true for plain objects', () => {
primitives.forEach((val, idx) => {
if (idx === 1 || idx === 2) {
expect(isPlainObject(val)).to.be.true
expect(_.isPlainObject(val)).to.be.true
} else {
expect(isPlainObject(val)).to.be.false
expect(_.isPlainObject(val)).to.be.false
}
})
})
})

describe('findKey', () => {
it('should return the matching key', () => {
const obj = {
simple: 1,
obj: {
val: 4,
},
}

const checkOne = val => val === 1
const checkTwo = val => typeof val === 'object'

expect(findKey(obj, checkOne)).to.deep.equal(_.findKey(obj, checkOne))
expect(findKey(obj, checkTwo)).to.deep.equal(_.findKey(obj, checkTwo))
})
})

describe('compact', () => {
it('removes falsy values', () => {
const values = [
true,
false,
10,
0,
null,
undefined,
NaN,
'',
'false, null, 0, "", undefined, and NaN are falsy',
]

expect(compact(values)).to.deep.equal(_.compact(values))
})
})

describe('flatten', () => {
it('flattens an array 1 level', () => {
const value = [1, [2, [3, [4]], 5, [[[6], 7], 8], 9]]
expect(flatten(value)).to.deep.equal(_.flatten(value))
})
})

describe('map', () => {
it('should map an array', () => {
const values = [1, 2, 3, 4]
const mapFn = val => val * 10

expect(map(values, mapFn)).to.deep.equal(_.map(values, mapFn))
expect(map(values, mapFn)).to.deep.equal([10, 20, 30, 40])

// ensure that values array is not mutated
expect(values).to.deep.equal([1, 2, 3, 4])
})

it('should map an object', () => {
const obj = {
one: 1,
two: 2,
three: 3,
}
const mapFn = (val, key) => `${key} - ${val * 10}`

expect(map(obj, mapFn)).to.deep.equal(_.map(obj, mapFn))
expect(map(obj, mapFn)).to.deep.equal([
'one - 10',
'two - 20',
'three - 30',
])

// ensure the object was not mutated
expect(obj).to.deep.equal({
one: 1,
two: 2,
three: 3,
})
})
})
})
4 changes: 4 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3130,6 +3130,10 @@ jsx-ast-utils@^1.0.0, jsx-ast-utils@^1.3.4:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1"

just-reduce-object@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/just-reduce-object/-/just-reduce-object-1.0.3.tgz#08b69499dba3504f7a46b73937b4cdf7a5a05a2e"

kind-of@^3.0.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
Expand Down