What are some ways to enhance this TypeScript code using Functional Programming with the FP-TS library?

i am struggling to write some typescript code using fp-ts

Below are the tasks that i want the algorithm to carry out:

Once a path is received from the command line, it should

  • check if the given path exists
  • search for all files in the directory and locate a file with the name cratb.import and one of the extensions ".json", ".yaml" or ".yml"
  • If the extension is ".json", parse the plain text into an object using JSON.parse. If it's ".yaml", use the js-yaml package to parse the plain text into an object with YAML.load

Here is the primary part of my code:

if(FpFs.pathExists(targetPath)){
  const res = await pipe(
    FpFs.readDir(targetPath),
    TE.map((files) =>
      O.fromNullable(files.find(e => e === `${dFileName}.yaml` || e === `${dFileName}.yml` || e === `${dFileName}.json`))
    ),
    TE.map(
      O.map(fileName =>
        ['json', 'JSON', 'yaml', 'YAML', 'yml', 'YML'].includes(getFileExtension(fileName))
          ? O.fromNullable(fileName)
          : O.fromNullable(null)
      )
    ),
    TE.map(O.flatten),
    TE.map(
      O.map(
        fileName =>
          ['json', 'JSON'].includes(getFileExtension(fileName))
            ? pipe(
                FpFs.readFile(path.join(targetPath, fileName)),
                TE.map(x => JSON.parse(x.toString()))
              )
            : pipe(
              FpFs.readFile(path.join(targetPath, fileName)),
              TE.map(x => YAML.load(x.toString()))
            )
      )
    )
  )()
  if(E.isRight(res)){
    if(O.isSome(res.right)){
      res.right.value()
      .then(res => {
        if(E.isRight(res)){
          return console.log(res.right)
        }
      })
    }
  }
  console.log('Error in some point XD')
}else{
  console.log(color.red(['ERROR']), `directory "${ importFilePath }" not found`)
}

I feel like there might be room for improvement in this code

Any suggestions would be greatly appreciated

Thank you

Answer №1

After conducting further research and collaborating with the community, I have developed the following code:

helpers.ts

import * as O from 'fp-ts/lib/Option'

export const appendStrBefore = (appending: string) => (appended: string) => `${appending}${appended}`

export const isOneOfOptions = 
  (...options: string[]) =>
  (searched: string) =>
  options.includes(searched)

export const candidatesContainingSomeOfOptions =
  (options: string[]) =>
  (candidates: string[]): O.Option<string> => {
    const result = options.reduce((prev, curr) => prev === '' ? candidates.includes(curr) ? curr : prev : prev, '')
    return result === '' ? O.none : O.some(result)
  }

export const getFileExtension = (fileName: string): string => {
  const lastPeriod = fileName.lastIndexOf('.')
  return fileName.substring(lastPeriod + 1, fileName.length)
}

Main File

(importFilePath = '', { test }) => {    
const targetPath = path.join(process.cwd(), importFilePath)
const dFileName = 'cratb.import'
const extOptions = ['json', 'JSON', 'yaml', 'YAML', 'yml', 'YML']
const readFileAndParse =
  (path: string) =>
  (parser: Function) =>
  pipe(
    FpFs.readFile(path),
    TE.map(x => parser(x.toString()))
  )

FpFs.pathExists(targetPath)
  ? pipe(
    FpFs.readDir(targetPath),
    TE.map(
      files => pipe(
        extOptions.map(appendStrBefore(`${dFileName}.`)),
        (candidates) => candidatesContainingSomeOfOptions(candidates)(files)
      )
    ),
    TE.map(
      fileNameOption => 
      O.isSome(fileNameOption)
        ? pipe(
          readFileAndParse(path.join(targetPath, fileNameOption.value)),
          parsing => parsing(
            isOneOfOptions('json', 'JSON')(getFileExtension(fileNameOption.value)) //choose a parser
              ? JSON.parse
              : YAML.load
          ),
        )
        : TE.of('File not found')
    ),
    TE.fold(
      err => T.of(handleFSError(err)),
      TE.fold(
        err => T.of(handleFSError(err)),
        T.of
      )
    )
  )().then(parseConfigObject)
  : console.log(color.red(['ERROR']), `directory "${ importFilePath }" not found`)

With these updates, I believe the code has been improved.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Steps to deactivating a styled button using React's styled-components:

I've created a very basic styled-components button as follows: import styled from 'styled-components'; const StyledButton = styled.button``; export const Button = () => { return <StyledButton>Default label</StyledButton> ...

Classes in Typescript can implement interfaces to streamline the functionality

Recently, I've been working on creating my custom class called AxiosError and I can't help but feel like the code is a bit repetitive. //types.ts export interface IAxiosRequest{} export interface IAxiosResponse{} export interface IAxios ...

Tips for effectively handling notifications using a single state management system

This React project showcases the Notification System demo provided by Mantine. It includes several function components utilizing notification. const A = () => { useEffect(() => { notifications.show({ // config }); }, []); retur ...

JavaScript/Typescript is throwing an error because it is unable to access the property 'username' of an undefined object

In my project, I am attempting to compile a list of Profile objects and then extract specific elements from each object in the list. To accomplish this, I have defined a public interface named Profile, imported it into my component, and instantiated a new ...

Using React.lazy, Suspense, and react-router-dom for code splitting in React does not function as intended

I'm currently working on setting up a simple example that is similar to the concept of lazy-loading route components as explained here: https://reactjs.org/docs/code-splitting.html#route-based-code-splitting The idea is to dynamically load ModuleOne ...

Distinguishing between TypeScript versions 2.0.x and 2.1.x using type definitions and filtering with a switch/case statement

@ngrx/store (an observable redux implementation for angular (2) ) utilizes a specific pattern to assign the correct type to a reducer. Check out the actual code here. export const ActionTypes = { FOO: type('foo'), BAR: type('bar&apos ...

Issue with Click event not working on dynamically added button in Angular 8

My goal is to dynamically add and remove product images when a user clicks the add or delete button on the screen. However, I am encountering an issue where the function is not being called when dynamically injecting HTML and binding the click event. Below ...

In React, the issue arises when a Typescript declaration merging cause is referenced as a value but is being mistakenly used as a type

I am trying to come up with a solution to avoid the hassle of brainstorming names that seamlessly incorporate suffixes or prefixes in order to differentiate between declarations and component names. After being inspired by this resource Avoid duplicate id ...

Is TypeScript 2.8 Making Type-Safe Reducers Easier?

After reading an insightful article on improving Redux type safety with TypeScript, I decided to simplify my reducer using ReturnType<A[keyof A]> based on the typeof myActionFunction. However, when creating my action types explicitly like this: exp ...

Mastering the art of theming components using styled-components and Material-UI

Can you integrate the Material-UI "theme"-prop with styled-components using TypeScript? Here is an example of Material-UI code: const useStyles = makeStyles((theme: Theme) => ({ root: { background: theme.palette.primary.main, }, })); I attemp ...

Show the current status of an API call in React using TypeScript

As a beginner in React and TypeScript, I'm working on calling a Graph API using POST method. Below is my code snippet: const OwnerPage: React.FunctionComponent = () => { const [TextFieldValue, setTextFieldValue] = React.useState('& ...

Error with object props in React using Typescript

Here's a scenario; I have a list of 'Reviews' that I am trying to render. The Proptype for these reviews is as follows: export interface Props { title: string; name: string; reviewdesc: string; rating: number; } In the pare ...

Ways to implement es6 in TypeScript alongside react, webpack, and babel

Being new to front-end development, I have found that following a simple tutorial can quickly help me start tackling problems in this field. One issue I've encountered is with ES5, which lacks some of the tools that are important to me, like key-value ...

Updating non-data properties dynamically in a custom AG Grid cell renderer

In my grid setup, I have implemented an editor button in a column for each row and a new item creator button outside the grid. One of the requirements is that all buttons should be disabled when either the create or edit button is clicked. To achieve thi ...

What is the process for finding GitHub users with a specific string in their name by utilizing the GitHub API

I'm looking to retrieve a list of users whose usernames contain the specific string I provide in my query. The only method I currently know to access user information is through another endpoint provided by the GitHub API, which unfortunately limits t ...

What is the process for extracting the elements of an array fetched from a service in Angular 2?

Currently, I am learning Angular 2 + PrimeNG and going through a quick start project available at the following link: https://github.com/primefaces/primeng-quickstart The project is a CRUD application and it functions flawlessly. The data is neatly displa ...

Guide to generating TypeScript output files within a non-hierarchical directory layout

In my project, I have a directory structure with multiple typescript files organized as follows: | src | app-1 | tsconfig.json | app-2 | tsconfig.json | common | standalone | tsconfig.json For each of the ...

Utilizing Typescript and sinon to mock the functionalities of jsonwebtoken

Looking for help with mocking the function verify in Typescript's jsonwebtoken library. I've installed typescript, jsonwebtoken, sinon, mocha, and chai along with their corresponding types. However, when trying to stub the function, an error occu ...

"Angular 4 is requesting a required get parameter that is currently missing

After running my code, I encountered the following console log error: "'Missing required 'page' parameter". I attempted to set this as a parameter in my get request, and it seemed successful because I was able to view the params as an array ...

Navigating an array using ngFor and encountering an error message saying, "Identifier not specified"

While using ngFor to iterate through an array, I encountered the following error message: "Identifier 'expenseitem' is not defined. The component declaration, template variable declarations, and element references do not contain such a memb ...