selfrefactor/rambda

Upcoming tasks

selfrefactor opened this issue · 22 comments

This is public TODO list for Rambda and Rambdax which is updated once a task is done:

wrong export

Revert export field changes in package.json due to ramda/ramda#3236

Data first Rambda

Rameda alike

As it is hard to create so many files, just exporting _ which will contain one file, much like the initial version of Rambda

Dictionary - type vs interface

#459 (comment)

isValid with functions

only arrow function works

ok(repos)(fn)
  // ok(repos)(x => {
  //     console.log({x})
  //   })

also not possible is array of function schema

ok(repos)([x => {
      console.log({x})
    }])

Methods to add:

  • whereAny
  • uniqBy
  • propSatisfies
  • pickBy
  • pathSatisfies
  • gte
  • mapObjIndexed(types from @types/ramda | added but types are not from there)

https://github.com/smartprocure/futil-js#differentlast
https://github.com/smartprocure/futil-js#whentruthy
findApply
compactMap
compactJoin
flattenObject
simpleDiff
highlight
on
off
includeLens?

Add R.mapToList which takes object and returns a list

include eslint-plugin-mocha as notable users

SKIPPED

Duplication of test, readme example and typings test. As it depends on REPL, documentation site needs to be build first.

The idea is to move build information from files/index.d.ts to the source files. Maybe run Jest test in browser instead of having REPL app.

apply for inclusion in https://github.com/hemanth/functional-programming-jargon once more FP functions are added

try transducers from Ramda to be included

Rambdax has issues with _consumetypings tests

  • Add R.mapAllSettled

Explanation: It asynchronously iterates over a list using Promise.allSettled.

import { delay } from './delay.js'
import { join } from './join.js'
import { map } from './map.js'
import { mapAllSettled } from './mapAllSettled.js'
import { pipeAsync } from './pipeAsync.js'

const fn = async (x, i) => {
await delay(100)
if (i % 2) throw new Error(foo-${ i })

return x + 1
}

test('happy', async () => {
await expect(mapAllSettled(fn, [ 1, 2, 3, 4 ])).resolves
.toMatchInlineSnapshot([ { "status": "fulfilled", "value": 2, }, { "reason": [Error: foo-1], "status": "rejected", }, { "status": "fulfilled", "value": 4, }, { "reason": [Error: foo-3], "status": "rejected", }, ])
})

test('inside pipe', async () => {
const result = await pipeAsync(
mapAllSettled(fn),
map(({ status }) => status),
join('-')
)([ 1, 2, 3 ])
expect(result).toBe('fulfilled-rejected-fulfilled')
})

===

export async function mapAllSettledFn(fn, arr){
const promised = arr.map((a, i) => fn(a, i))

return Promise.allSettled(promised)
}

export function mapAllSettled(fn, arr){
if (arguments.length === 1){
return async holder => mapAllSettledFn(fn, holder)
}

return new Promise((resolve, reject) => {
mapAllSettledFn(fn, arr).then(resolve)
.catch(reject)
})
}

restore

import isCI from 'is-ci'
import { resolve } from 'path'
import { execCommand } from '../files/execCommand.js'

jest.setTimeout(3 * 60 * 1000)

/**
 * "consume-typings:clone": "cd .. && git clone --depth 1 https://github.com/selfrefactor/rambda-scripts.git rambda-scripts-clone",
		"consume-typings:execute": "cd ../rambda-scripts-clone/scripts/consume-typings && yarn start",
		"consume-typings": "yarn consume-typings:clone && yarn consume-typings:execute",
 */
const DIR = resolve(__dirname, '../../')

test('typings can be imported', async () => {
  if (!isCI) return
  await execCommand('rm -rf rambda-scripts-clone', DIR)
  await execCommand('yarn build:main')
  expect(await execCommand('yarn consume-typings')).toBeTrue()
})

import { pathFn } from './path.js'

export const removePath = (object, path) => {
  const pathResult = pathFn(path, object)
  if (pathResult === undefined) return object
  if (!path.length) return object

  const [ head, ...tail ] = path
  if (tail.length === 0){
    const { [ head ]: _, ...rest } = object

    return rest
  }

  if (!object[ head ]) return object

  return {
    ...object,
    [ head ] : removePath(object[ head ], tail),
  }
}

export function omitPaths(paths, obj){
  if (arguments.length === 1){
    return _obj => omitPaths(paths, _obj)
  }

  return paths.reduce((result, path) => {
    const pathParts = path.split('.')

    return removePath(result, pathParts)
  }, obj)
}

---
import { omitPaths } from './omitPaths.js'

const object = {
  a : {
    b : {
      c : 1,
      d : 2,
    },
  },
  foo : {
    bar : 3,
    baz : 4,
  },
}

test('happy', () => {
  const result = omitPaths([ 'a.b.c', 'foo.bar' ], object)
  const curried = omitPaths([ 'a.b.c', 'foo.bar' ])
  const expected = {
    a   : { b : { d : 2 } },
    foo : { baz : 4 },
  }
  expect(result).toEqual(expected)
  expect(curried(object)).toEqual(expected)
})

test('with no matching path', () => {
  expect(omitPaths([ 'a.b.c.d.e.f', 'foo.bar.123' ], object)).toEqual(object)
})