简体   繁体   中英

fp-ts, how to take an array of TaskEithers, run a function in each item then split the options into two arrays?

I am trying to write the following code with fp-ts.

imperative:

export async function runTest(globString) {
  let passed = 0;
  let failed = 0;
  const files = glob.sync(globString);
  for (let i = 0; i < files.length; i++) {
    // eslint-disable-next-line no-await-in-loop
    const module = await import(`./${path.relative(__dirname, files[i])}`);
    for (let z = 0; z < Object.keys(module).length; z++) {
      const testFn = Object.keys(module)[z];
      // eslint-disable-next-line no-await-in-loop
      const result = await module[testFn]()
      // eslint-disable-next-line no-plusplus
      if (result) { passed++ } else { failed++ };
      console.log(`${result ? `✅` : `❌`} ${module[testFn].description || testFn}`)
    }
  }
  console.log(`✅ ${passed} tests passed`);
  console.log(`❌ ${failed} tests failed`);
}

the functions applied can be divided into two:

the one that imports the file from the glob. the second that runs the function.

We can even omit the console logs, I am stuck where I should read the right values but I am not what should to that the data out of this Right, and also eventually have the Left in a separated array. Any ideas?

const importModule = (string) => import(`./${path.relative(__dirname, string)}`)
export const runTest = (globString) => pipe(
  glob.sync(globString),
  AR.map(TE.tryCatchK(importModule, id)),
  AR.map(TE.bimap(id, Object.values)),
  AR.map(TE.bimap(id, AR.map(fn => [fn(), fn.name]))),
  async a => console.log(await a[0]()) //{_tag: 'Right', right: Array(15)}
)
//number of items is correct but I am stuck here.

EDIT:

got the code improved now it works by capturing the errors into the Eithers and I do have an array of Eithers.

export const runTest = (globString) => pipe(
  glob.sync(globString),
  x => [...x, 'tras'], //last item will throw an error it is on purpose
  AR.map(TE.tryCatchK(async str => Object.values((await importModule(str))), id)),
  AR.sequence(T.ApplicativePar),
  async a => (await a()).map(console.log)
)

Now the rights in the Array are arrays as well, so I have Task<Array<Either<E,Array>>> and I need Task<Array<Either<E,Function>, problem now is that if I try to sequence I lose the rights

For anyone wondering I ended up with the following.

const safeRunFn = f => TE.tryCatchK(
  async (s) => await f() && `✅ ${f.description || f.name} - passed`,
  (e) => `❌ ${f.description || f.name} - failed \n${e}`
)(f);

const safeImport = z => TE.tryCatchK(
  (s) => import(`./${path.relative(__dirname, s)}`),
  (e) => `❌ ${z} - failed \n${e}`
)(z);

export const runTest = (globString) => pipe(
  glob.sync(globString),
  x => [...x, 'tras'],
  A.map(safeImport),
  A.map(TE.map(Object.values)),
  A.map(TE.chain(TE.traverseArray(safeRunFn))),
  A.map(TE.match(id, id)),
  T.sequenceArray,
  T.map(x => x.flat())
  //A.flatten throws the error below, not sure why.
  //Uncaught TypeError TypeError: CreateListFromArrayLike called on non-object
)

Any ideas how this can be improved are welcome.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM