in typescript recursive reduce ~ read.

Building a folder structure tree recursively with typescript and reduce

Recenlty i was working on a new CLI tool for my company, where we would have to work a lot with file system and files manipulation. For one of the tasks i needed to have a method that would generate me a directory structure in JSON format with all child directories and files listed. Now, i have to admit, that I still have struggles with reduce methods, but here it was exactly what i needed and , to be honest, I'm a bit proud of the solution i managed to get. My small personal victory. I'm writing it here, so that future me could use this and also I really hope that it will help others, who face with this problem as well. Here's what the method looks like :

import fs, { readdirSync, statSync } from 'fs'
import { dirname, resolve } from 'path'
export type GenericObject = Record<string, unknown>

export const getListOfFilesInDirectory = (dirPath: string): string[] => {
    return readdirSync(dirPath).filter((entry) => statSync(resolve(dirPath, entry)).isFile())
}

export const getListOfDirectoriesInDirectory = (dirPath: string): string[] => {
    return readdirSync(dirPath).filter((entry) => statSync(resolve(dirPath, entry)).isDirectory())
}

export const describeDirStructure = (dirPath: string): GenericObject => {
    return readdirSync(dirPath).reduce((acc: GenericObject, currentPointer: string) => {
        if (statSync(resolve(dirPath, currentPointer)).isDirectory()) {
            const files: string[] = getListOfFilesInDirectory(resolve(dirPath, currentPointer))
            const dirs: string[] = getListOfDirectoriesInDirectory(resolve(dirPath, currentPointer))
            if (files.length > 0 && dirs.length > 0) {
                const innerStructure = {
                    [currentPointer]: {
                        files,
                        ...describeDirStructure(resolve(dirPath, currentPointer)),
                    },
                }
                acc = {
                    ...acc,
                    ...innerStructure,
                }
                return acc
            }
            if (dirs.length === 0 && files.length > 0) {
                acc = {
                    ...acc,
                    ...{ [currentPointer]: files },
                }
            } else {
                acc = {
                    ...acc,
                    ...{ [currentPointer]: describeDirStructure(resolve(dirPath, currentPointer)) },
                }
            }
        }
        return acc
    }, {})
}

In order to verify this, i made a simple directory example that looks like this :

└── list-directory-example
    └── demo
        ├── service-data
        │   ├── service-details.json
        │   └── transactions
        │       └── transactions.json
        └── user-data
            ├── billing.json
            └── personal-information.json

And the unit test is also quite simple :

    test('🟢 I can get a full list of all files in all directories recursively', () => {
        const result = describeDirStructure(
            resolve('./src/utils/__tests__/fixtures', 'list-directory-example')
        )
        expect(result).toEqual({
            demo: {
                'service-data': {
                    files: ['service-details.json'],
                    transactions: ['transactions.json'],
                },
                'user-data': ['billing.json', 'personal-information.json'],
            },
        })
    })

I really hope that this will be helpful not only for me, but for others as well.

Happy coding everyone ! ☺️

comments powered by Disqus
comments powered by Disqus