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

What issues can trailing white space cause in TypeScript coding?

While I understand that linting is the reason for this, why are trailing spaces considered problematic? I plan to disable this feature in tslint.json, but before I make that change, I want to ensure I'm not making a mistake. Visual Studio Code alert ...

Experiencing a useContext error when implementing MDX with NextJS 13

I am currently working on integrating mdx files into Next.js 13. After completing all necessary configurations in next.config and creating the file structure, I have the following path within the app folder: > docs > components > accordion > pa ...

Utilizing Angular to Handle Undefined Variables in String Interpolation

Seeking a way to showcase data obtained from an external API on a webpage using Angular's string interpolation. If no data is retrieved or is still pending, the aim is to display 'N/A'. An attempt was made following this method, but encoun ...

Inferring object types through direct values

This code example has a lot of detail: interface Coordinate { latitude: 40.7128; longitude: -74.0060; } const location: Coordinate = { latitude: 40.7128, longitude: -74.0060, }; // The inferred type would have been // { x: number; y: number; } I ...

The function has been called but it did not return a

It seems that there is confusion surrounding the .toHaveBeenCalled() Matcher in Jasmine. While it should return a Promise that resolves when the function has been called, some users are experiencing it returning undefined instead. For example: it('sh ...

Exploring the TypeScript Type System: Challenges with Arrays Generated and Constant Assertions

I am currently grappling with a core comprehension issue regarding TypeScript, which is highlighted in the code snippet below. I am seeking clarification on why a generated array does not function as expected and if there is a potential solution to this pr ...

What is the best way to invoke a method within the onSubmit function in Vuejs?

I am facing an issue with a button used to log in the user via onSubmit function when a form is filled out. I also need to call another method that will retrieve additional data about the user, such as privileges. However, I have been unsuccessful in makin ...

Error occurs in the compiler when a variable is utilized as a function

I'm currently facing an issue while compiling Typescript where the compiler is throwing an error: TypeError: myVariable is not a function at Object.<anonymous> (/home/anon/Desktop/Typescript/main.js:37:1) at Module._compile (internal/mo ...

Creating a message factory in Typescript using generics

One scenario in my application requires me to define message structures using a simple TypeScript generic along with a basic message factory. Here is the solution I devised: export type Message< T extends string, P extends Record<string, any> ...

Click on the button to open the generated link in a new tab

How can I efficiently open a URL in a new tab after making an API call with the click of a button? Currently, the button triggers the API call and generates the URL. <button (click)="getUrl()">Connect</button> In TypeScript: getUrl() ...

Which superclass does ReadonlyArray extend from?

Looking at this TypeScript code snippet: const arr: ReadonlyArray<string> = [ "123", "234" ]; arr.push("345"); An error is thrown by the TS compiler: Property 'push' does not exist on type 'ReadonlyArray<string>&apo ...

I'm having trouble with VSCode deleting my TypeScript code. Is there a way to disable this feature

My code keeps getting removed and I can't figure out how to stop it. Does anyone know which setting I need to adjust? Watch the video here: This issue occurs in all instances, not just with imports. ...

The RazorPay callback encountered an Uncaught TypeError indicating that the function is not recognized

In my TypeScript class, I have a defined handler as follows: "handler": function (response) { this.sendUserStatus(); }, Unfortunately, when I attempt to call this.sendUserStatus();, I encounter the following error: Uncaught Typ ...

Learn how to generate specific error messages based on the field that caused the failure of the @Column({ unique: true }) Decorator. Error code 23505

Hey there! I'm currently facing an issue while trying to handle Sign Up exceptions in my code. I want to inform the user if their username OR email is already in use. Although using the decorator @Column({ unique: true}) allows me to catch error 23505 ...

Error TS2488 in React TypeScript: The data type 'IStateTypes' is required to have a method called '[Symbol.iterator]()' that returns an iterator

At the moment, I am working on implementing a global state in React Hooks but have run into an issue. https://i.stack.imgur.com/DN83K.png The current problem I'm facing is with [Symbol.iterator](. I am uncertain about how to resolve this as I am in ...

Different methods to prompt TypeScript to deduce the type

Consider the following code snippet: function Foo(num: number) { switch (num) { case 0: return { type: "Quz", str: 'string', } as const; case 1: return { type: "Bar", 1: 'value' } as const; default: thr ...

Generate an object in Typescript that includes a dynamic property calculated from an input parameter

Is there a way to achieve the following function in TypeScript? function f<T extends 'a' | 'b'>(t : T): {[t]: ...} { return {[t]: ...} } This code is intended to make f('a') have type {'a': ...} and similarl ...

Apologies, but there was an error attempting to differentiate 'nombreyo'. Please note that only arrays and iterables are permitted for this action

Encountering an error while attempting to display a class in the HTML. <li> <ul> <li *ngFor="let refac of refactormodel" > -- word_to_rename: {{refac.word_to_rename}} -- renowned_word: {{refac.renowned_word}} ...

What is causing the issue where search query parameters are not recognizing the initially selected option?

Hey, I'm having an issue with searchParams. The problem is that when I apply filters like "Breakfast, Lunch, Dinner", the first chosen option isn't showing up in the URL bar. For example, if I choose breakfast nothing happens, but if I choose lun ...

Make the download window appear automatically when downloading a file

How can I use JavaScript/TypeScript to prompt the browser to open the download window? My goal is to give users the ability to rename the file and select the download folder, as most downloads are saved directly in the default location. This is how I curr ...