简体   繁体   中英

Purifying function to create array of/from File Directory Structure

I have been working on a function which would take a relative directory name, recursively iterate through the directory and all its sub-directories, and create an array of the entire structure including the files.

I started with the work done here: https://gist.github.com/kethinov/6658166

I am developing for a standalone app and can take advantage of ES6/ES7.

The following code works. However, my main goal is to improve my coding skills so I am wondering if there is a better way? More efficient? More functional?

I know I can move the named function directly into the .map and use an arrow function but should I? In this case I am not really returning anything so is using the more concise syntax less clear? The fact that I am not explicitly returning and utilizing that return but rather relying on a side effect(?) is not functional.

const fs = require('fs');
const path = require('path');


function walkSync(dir, array = []) {

  function _process(collectionElement) {

    const nextJoin = path.join(dir, collectionElement);
    array.push(nextJoin.replace(/\\/g, '/'));

    if (fs.statSync(nextJoin).isDirectory()) {

      walkSync(nextJoin, array);

    }

  }

  fs.readdirSync(dir).map(_process);

  return array;

}

console.log(walkSync('directory'));

Edited 4/23/17

So I believe the following is more functional and 'purer'. Not sure if I could still do better?

const fs = require('fs');
const path = require('path');


// Builds an array of all directories and files
function processDirectory(content, directory, array) {

  const item = path.join(directory, content);

  // reformat for Windows environment
  array.push(item.replace(/\\/g, '/'));

  if (fs.statSync(item).isDirectory()) {

    // eslint-disable-next-line no-use-before-define
    return walkDirectorySync(item, array);

  }

  return array;

}

function walkDirectorySync(directory, array = []) {

  // node reads the directory SYNCHRONOUSLY (maintains order & BLOCKS)
  fs.readdirSync(directory).map(content => processDirectory(content, directory, array));

  return array;

}


console.log(walkDirectorySync('world'));

Brought in the lodash module here. First, you can change map to reduce in walkDirectorySync and pass it one array instead of injecting one. Second you can curry the processDirectory function which will allow you to curry directory into processDirectory and have the curried function be passed to each iteration of reduce. This turns processDirectory into a reducing function. Finally you can be more pure by cloning the array inside processDirectory and not modifying the original -- of course at a performance cost, but thats functional for you.

This should represent a more pure / functional approach. I'm sure there is always room for more improvement, but hope this gives you some food for thought.

const fs     = require('fs'),
      lodash = require('lodash'),
      path   = require('path');

function walkDirectorySync(directory) {
  return fs.readdirSync(directory).reduce(processDirectory(directory), []);
}

const processDirectory = lodash.curry(function (directory, accumulator, content) {
  accumulator = accumulator.slice(); // trying to be pure here

  const item = path.join(directory, content).replace(/\\/g, '/'); // reformats for Windows environment

  accumulator.push(item);

  if (fs.statSync(item).isDirectory()) {
    // eslint-disable-next-line no-use-before-define
    accumulator.push(...walkDirectorySync(item));
  }

  return accumulator;
});

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