Skip to content

Commit e1c73b3

Browse files
committed
Implemented parallel
Signed-off-by: Jaid <jaid.jsx@gmail.com>
1 parent b49f8dd commit e1c73b3

File tree

2 files changed

+101
-12
lines changed

2 files changed

+101
-12
lines changed

src/index.js

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,36 +8,91 @@
88
* @returns {*} Anything that will be the object entry value
99
*/
1010

11+
/**
12+
* @typedef asyncValueGenerator
13+
* @type {function}
14+
* @async
15+
* @param {string} value Original array entry
16+
* @param {number} index Index of the array entry (starts at 0)
17+
* @returns {*} Anything that will be the object entry value
18+
*/
19+
20+
const emptyReturn = {}
21+
1122
/**
1223
* Converts an array to an object with static keys and customizable values
1324
* @example
1425
* import arrayToObjectKeys from "array-to-object-keys"
15-
* arrayToObjectKeys(["a", "b"])
16-
* // {a: null, b: null}
26+
* let result = arrayToObjectKeys(["a", "b"])
27+
* result = {a: null, b: null}
1728
* @example
1829
* import arrayToObjectKeys from "array-to-object-keys"
19-
* arrayToObjectKeys(["a", "b"], "value")
20-
* // {a: "value", b: "value"}
30+
* let result = arrayToObjectKeys(["a", "b"], "value")
31+
* result = {a: "value", b: "value"}
2132
* @example
2233
* import arrayToObjectKeys from "array-to-object-keys"
23-
* arrayToObjectKeys(["a", "b"], (key, index) => `value for ${key} #${index + 1}`)
24-
* // {a: "value for a #1", b: "value for b #2"}
34+
* let result = arrayToObjectKeys(["a", "b"], (key, index) => `value for ${key} #${index + 1}`)
35+
* result = {a: "value for a #1", b: "value for b #2"}
2536
* @function
2637
* @param {string[]} array Keys for the generated object
2738
* @param {valueGenerator|*} [valueGenerator=null] Optional function that sets the object values based on key and index
2839
* @returns {object<string, *>} A generated object based on the array input
2940
*/
3041
export default (array, valueGenerator = null) => {
31-
if (!Array.isArray(array)) {
32-
return {}
42+
if (!Array.isArray(array) || !array.length) {
43+
return emptyReturn
3344
}
3445
const object = {}
3546
if (typeof valueGenerator === "function") {
36-
let index = 0
47+
array.forEach((key, index) => {
48+
object[key] = valueGenerator(key, index)
49+
})
50+
} else {
3751
for (const value of array) {
38-
object[value] = valueGenerator(value, index)
39-
index++
52+
object[value] = valueGenerator
53+
}
54+
}
55+
return object
56+
}
57+
58+
/**
59+
* Converts an array to an object with static keys and customizable values
60+
* @example
61+
* import fs from "fs"
62+
* import path from "path"
63+
* import {parallel} from "array-to-object-keys"
64+
* const keys = ["license", "readme", "package", ".travis", "not-here"]
65+
* const valueGenerator = async name => {
66+
* const files = await fs.promises.readdir(path.resolve(__dirname, ".."))
67+
* for (const file of files) {
68+
* if (file.startsWith(`${name}.`)) {
69+
* const stat = await fs.promises.stat(path.resolve(__dirname, "..", file), "utf8")
70+
* return stat.size
71+
* }
72+
* }
73+
* return null
74+
* }
75+
* let result = await parallel(keys, valueGenerator)
76+
* result = { ".travis": 1672, license: 1099, package: 1948, readme: 132, "not-here": null }
77+
* @function
78+
* @param {string[]} array Keys for the generated object
79+
* @param {asyncValueGenerator|*} [valueGenerator=null] Async function that sets the object values based on key and index
80+
* @returns {object<string, *>} A generated object based on the array input
81+
*/
82+
export const parallel = async (array, valueGenerator = null) => {
83+
if (!Array.isArray(array) || !array.length) {
84+
return emptyReturn
85+
}
86+
const object = {}
87+
if (typeof valueGenerator === "function") {
88+
for (const key of array) {
89+
object[key] = null // Setting object keys synchronously to ensure order
4090
}
91+
const jobs = array.map(async (key, index) => {
92+
const value = await valueGenerator(key, index)
93+
object[key] = value
94+
})
95+
await Promise.all(jobs)
4196
} else {
4297
for (const value of array) {
4398
object[value] = valueGenerator

test/test.js

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import path from "path"
2+
import fs from "fs"
23

34
const indexModule = process.env.MAIN ? path.resolve(__dirname, "..", process.env.MAIN) : path.join(__dirname, "..", "src")
4-
const {default: arrayToObjectKeys} = require(indexModule)
5+
const {default: arrayToObjectKeys, parallel} = require(indexModule)
56

67
it("should run with 1 argument", () => {
78
const result = arrayToObjectKeys(["a", "b"])
@@ -26,4 +27,37 @@ it("should run with a function as second argument", () => {
2627
a: "1-a-x",
2728
b: "2-b-x",
2829
})
30+
})
31+
32+
it("should run in parallel", async () => {
33+
const valueGenerator = (key, index) => `${index + 1}-${key}-x`
34+
const result = await parallel(["a", "b"], valueGenerator)
35+
expect(result).toEqual({
36+
a: "1-a-x",
37+
b: "2-b-x",
38+
})
39+
})
40+
41+
it("should call fs functions in parallel", async () => {
42+
const keys = ["license", "readme", "package", ".travis", "not-here"]
43+
const valueGenerator = async name => {
44+
const files = await fs.promises.readdir(path.resolve(__dirname, ".."))
45+
for (const file of files) {
46+
if (file.startsWith(`${name}.`)) {
47+
const stat = await fs.promises.stat(path.resolve(__dirname, "..", file), "utf8")
48+
return stat.size
49+
}
50+
}
51+
return null
52+
}
53+
const result = await parallel(keys, valueGenerator)
54+
expect(keys).toEqual(["license", "readme", "package", ".travis", "not-here"])
55+
expect(Object.keys(result)).toEqual(keys)
56+
expect(result).toMatchObject({
57+
license: expect.any(Number),
58+
readme: expect.any(Number),
59+
package: expect.any(Number),
60+
".travis": expect.any(Number),
61+
"not-here": null,
62+
})
2963
})

0 commit comments

Comments
 (0)