Node search for file upwards - node.js

I'm looking for a function in node.js to search upwards in the filesystem to check if a given file exists and if so get its content.
For example, if I have the following folder structure:
* root
|--dir1
| |-dir2
| |-dir3
|...
If I'm in dir3 I want to search for a given file that could be in any folder if I go up .. but not in their subfolders. So what I want is a simple way to check in current folder for the file if it doesn't exist go up one folder and search there, until you find the file or you are in the root folder.

I think it's easy to write by yourself. You can use fs.readdir or fs.readdirSync.
Synchronous solution might look like this: (not tested)
var fs = require('fs');
var process = require('process');
var path = require('path');
function findFile(filename, startdir) {
if(!startdir) statdir = process.cwd();
while(true) {
var list = fs.readdirSync(startdir);
if((index = list.indexOf(filename)) != -1)
// found
return fs.readFileSync(path.join([startdir, filename]));
else if(startdir == '/')
// root dir, file not found
return null;
else
startdir = path.normalize(path.join([startdir, '..']));
}
}

There is also an NPM package - fileUp that does this.
From the Readme:
const path = require('path');
const findUp = require('find-up');
(async () => {
console.log(await findUp('unicorn.png'));
//=> '/Users/sindresorhus/unicorn.png'
console.log(await findUp(['rainbow.png', 'unicorn.png']));
//=> '/Users/sindresorhus/unicorn.png'
console.log(await findUp(async directory => {
const hasUnicorns = await findUp.exists(path.join(directory, 'unicorn.png'));
return hasUnicorns && directory;
}, {type: 'directory'}));
//=> '/Users/sindresorhus'
})();

Related

How can I use Node.js fs to sort a set of folders according to their created date?

I'm building a node.js application in which I need to read all the folders in a parent folder and display their names in the order they were created on the page. Here is what I have so far:
function getMixFolders() {
const { readdirSync } = require('fs');
const folderInfo = readdirSync('./shahspace.com/music mixes/')
.filter(item => item.isDirectory() && item.name !== 'views');
return folderInfo.map(folder => folder.name);
}
As you can see, I haven't implemented sorting. This is because readdirSync doesn't return the information I need. The only things it returns are the name of the folder and something called the Symbol(type) (which seems to indicate whether its a folder or file).
Is there another method for getting more details about the folders I'm reading from the parent folder? Specifically the created date?
There is no super efficient way in nodejs to get a directory listing and get statistics on each item (such as createDate). Instead, you have to distill the listing down to the files/folders you're interested in and then call fs.statSync() (or one of the similar variants) on each one to get that info. Here's a working version that looks like it does what you want:
Get directory list using the {withFileTypes: true} option
Filter to just folders
Ignore any folders named "views"
Get createDate of each folder
Sort the result by that createDate in ascending order (oldest folders first)
This code can be run as it's own program to test:
const fs = require('fs');
const path = require('path');
const mixPath = './shahspace.com/music mixes/';
function getMixFolders() {
const folderInfo = fs.readdirSync(mixPath, { withFileTypes: true })
.filter(item => item.isDirectory() && item.name !== 'views')
.map(folder => {
const fullFolderPath = path.join(path.resolve(mixPath), folder.name);
const stats = fs.statSync(fullFolderPath);
return { path: fullFolderPath, ctimeMs: stats.ctimeMs }
}).sort((a, b) => {
return a.ctimeMs - b.ctimeMs;
});
return folderInfo;
}
let result = getMixFolders();
console.log(result);
If you wanted the final array to be only the folder names without the createDates you could add one more .map() to transform the final result.

readdirSync cannot read encrypted home folder when accessing it directly

const fs = require("fs")
//const HOW = "/home/test/everything"
// const HOW = "/home/test/"
// This one fails. My home is encrypted and it cannot read directories, it gets the .Private file. I want to read files and directories in my home folder. But can't.
const HOW = "/home/test/folder/"
// This one works for some reason. It lists all the directories in the folder.
// const HOW = "folder"
// This one works as well
var list = walk(HOW)
console.log(list)
// How do I get contents of /home/test (which happens to be my home folder).
// I'm both root and "test" user of the computer.
I'd like to have walk() work on /home/test/.
The code that fails:
var walk = function(dir) {
var results = []
var list = fs.readdirSync(dir)
list.forEach(function(file) {
file = dir + '/' + file
var stat = fs.statSync(file)
if (stat && stat.isDirectory()) results = results.concat(walk(file))
else results.push(file)
})
return results
}
The exact line causing it (stack trace): var stat = fs.statSync(file)
The error is:
Error: ENOENT: no such file or directory, stat '/home/test/.Private/###############################################################'
Where # is an amount of letters whose importance to safety is unknown to me.
Node.js doesn't have a problem addressing any folder contained within my home folder, but cannot address the home folder itself. Neither my own account nor root account can get access to it.
I think you are adding an unnecessary /. Try changing
const HOW = "/home/test/folder/"
to
const HOW = "/home/test/folder"

How to create full path with node's fs.mkdirSync?

I'm trying to create a full path if it doesn't exist.
The code looks like this:
var fs = require('fs');
if (!fs.existsSync(newDest)) fs.mkdirSync(newDest);
This code works great as long as there is only one subdirectory (a newDest like 'dir1') however when there is a directory path like ('dir1/dir2') it fails with
Error: ENOENT, no such file or directory
I'd like to be able to create the full path with as few lines of code as necessary.
I read there is a recursive option on fs and tried it like this
var fs = require('fs');
if (!fs.existsSync(newDest)) fs.mkdirSync(newDest,'0777', true);
I feel like it should be that simple to recursively create a directory that doesn't exist. Am I missing something or do I need to parse the path and check each directory and create it if it doesn't already exist?
I'm pretty new to Node. Maybe I'm using an old version of FS?
Update
NodeJS version 10.12.0 has added a native support for both mkdir and mkdirSync to create a directory recursively with recursive: true option as the following:
fs.mkdirSync(targetDir, { recursive: true });
And if you prefer fs Promises API, you can write
fs.promises.mkdir(targetDir, { recursive: true });
Original Answer
Create directories recursively if they do not exist! (Zero dependencies)
const fs = require('fs');
const path = require('path');
function mkDirByPathSync(targetDir, { isRelativeToScript = false } = {}) {
const sep = path.sep;
const initDir = path.isAbsolute(targetDir) ? sep : '';
const baseDir = isRelativeToScript ? __dirname : '.';
return targetDir.split(sep).reduce((parentDir, childDir) => {
const curDir = path.resolve(baseDir, parentDir, childDir);
try {
fs.mkdirSync(curDir);
} catch (err) {
if (err.code === 'EEXIST') { // curDir already exists!
return curDir;
}
// To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows.
if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure.
throw new Error(`EACCES: permission denied, mkdir '${parentDir}'`);
}
const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1;
if (!caughtErr || caughtErr && curDir === path.resolve(targetDir)) {
throw err; // Throw if it's just the last created dir.
}
}
return curDir;
}, initDir);
}
Usage
// Default, make directories relative to current working directory.
mkDirByPathSync('path/to/dir');
// Make directories relative to the current script.
mkDirByPathSync('path/to/dir', {isRelativeToScript: true});
// Make directories with an absolute path.
mkDirByPathSync('/path/to/dir');
Demo
Try It!
Explanations
[UPDATE] This solution handles platform-specific errors like EISDIR for Mac and EPERM and EACCES for Windows. Thanks to all the reporting comments by #PediT., #JohnQ, #deed02392, #robyoder and #Almenon.
This solution handles both relative and absolute paths. Thanks to #john comment.
In the case of relative paths, target directories will be created (resolved) in the current working directory. To Resolve them relative to the current script dir, pass {isRelativeToScript: true}.
Using path.sep and path.resolve(), not just / concatenation, to avoid cross-platform issues.
Using fs.mkdirSync and handling the error with try/catch if thrown to handle race conditions: another process may add the file between the calls to fs.existsSync() and fs.mkdirSync() and causes an exception.
The other way to achieve that could be checking if a file exists then creating it, I.e, if (!fs.existsSync(curDir) fs.mkdirSync(curDir);. But this is an anti-pattern that leaves the code vulnerable to race conditions. Thanks to #GershomMaes comment about the directory existence check.
Requires Node v6 and newer to support destructuring. (If you have problems implementing this solution with old Node versions, just leave me a comment)
A more robust answer is to use use mkdirp.
var mkdirp = require('mkdirp');
mkdirp('/path/to/dir', function (err) {
if (err) console.error(err)
else console.log('dir created')
});
Then proceed to write the file into the full path with:
fs.writeFile ('/path/to/dir/file.dat'....
One option is to use shelljs module
npm install shelljs
var shell = require('shelljs');
shell.mkdir('-p', fullPath);
From that page:
Available options:
p: full path (will create intermediate dirs if necessary)
As others have noted, there's other more focused modules. But, outside of mkdirp, it has tons of other useful shell operations (like which, grep etc...) and it works on windows and *nix
Edit: comments suggest this doesn't work on systems that don't have mkdir cli instances. That is not the case. That's the point shelljs - create a portable cross platform set of shell like functions. It works on even windows.
fs-extra adds file system methods that aren't included in the native fs module. It is a drop in replacement for fs.
Install fs-extra
$ npm install --save fs-extra
const fs = require("fs-extra");
// Make sure the output directory is there.
fs.ensureDirSync(newDest);
There are sync and async options.
https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureDir.md
Using reduce we can verify if each path exists and create it if necessary, also this way I think it is easier to follow. Edited, thanks #Arvin, we should use path.sep to get the proper platform-specific path segment separator.
const path = require('path');
// Path separators could change depending on the platform
const pathToCreate = 'path/to/dir';
pathToCreate
.split(path.sep)
.reduce((prevPath, folder) => {
const currentPath = path.join(prevPath, folder, path.sep);
if (!fs.existsSync(currentPath)){
fs.mkdirSync(currentPath);
}
return currentPath;
}, '');
This feature has been added to node.js in version 10.12.0, so it's as easy as passing an option {recursive: true} as second argument to the fs.mkdir() call.
See the example in the official docs.
No need for external modules or your own implementation.
i know this is an old question, but nodejs v10.12.0 now supports this natively with the recursive option set to true. fs.mkdir
// Creates /tmp/a/apple, regardless of whether `/tmp` and /tmp/a exist.
fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => {
if (err) throw err;
});
Now with NodeJS >= 10.12.0, you can use fs.mkdirSync(path, { recursive: true }) fs.mkdirSync
Example for Windows (no extra dependencies and error handling)
const path = require('path');
const fs = require('fs');
let dir = "C:\\temp\\dir1\\dir2\\dir3";
function createDirRecursively(dir) {
if (!fs.existsSync(dir)) {
createDirRecursively(path.join(dir, ".."));
fs.mkdirSync(dir);
}
}
createDirRecursively(dir); //creates dir1\dir2\dir3 in C:\temp
You can simply check folder exist or not in path recursively and make the folder as you check if they are not present. (NO EXTERNAL LIBRARY)
function checkAndCreateDestinationPath (fileDestination) {
const dirPath = fileDestination.split('/');
dirPath.forEach((element, index) => {
if(!fs.existsSync(dirPath.slice(0, index + 1).join('/'))){
fs.mkdirSync(dirPath.slice(0, index + 1).join('/'));
}
});
}
You can use the next function
const recursiveUpload = (path: string) => {
const paths = path.split("/")
const fullPath = paths.reduce((accumulator, current) => {
fs.mkdirSync(accumulator)
return `${accumulator}/${current}`
})
fs.mkdirSync(fullPath)
return fullPath
}
So what it does:
Create paths variable, where it stores every path by itself as an element of the array.
Adds "/" at the end of each element in the array.
Makes for the cycle:
Creates a directory from the concatenation of array elements which indexes are from 0 to current iteration. Basically, it is recursive.
Hope that helps!
By the way, in Node v10.12.0 you can use recursive path creation by giving it as the additional argument.
fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => {
if (err) throw err;
});
https://nodejs.org/api/fs.html#fs_fs_mkdirsync_path_options
Too many answers, but here's a solution without recursion that works by splitting the path and then left-to-right building it back up again
function mkdirRecursiveSync(path) {
let paths = path.split(path.delimiter);
let fullPath = '';
paths.forEach((path) => {
if (fullPath === '') {
fullPath = path;
} else {
fullPath = fullPath + '/' + path;
}
if (!fs.existsSync(fullPath)) {
fs.mkdirSync(fullPath);
}
});
};
For those concerned about windows vs Linux compatibility, simply replace the forward slash with double backslash '\' in both occurrence above but TBH we are talking about node fs not windows command line and the former is pretty forgiving and the above code will simply work on Windows and is more a complete solution cross platform.
const fs = require('fs');
try {
fs.mkdirSync(path, { recursive: true });
} catch (error) {
// this make script keep running, even when folder already exist
console.log(error);
}
An asynchronous way to create directories recursively:
import fs from 'fs'
const mkdirRecursive = function(path, callback) {
let controlledPaths = []
let paths = path.split(
'/' // Put each path in an array
).filter(
p => p != '.' // Skip root path indicator (.)
).reduce((memo, item) => {
// Previous item prepended to each item so we preserve realpaths
const prevItem = memo.length > 0 ? memo.join('/').replace(/\.\//g, '')+'/' : ''
controlledPaths.push('./'+prevItem+item)
return [...memo, './'+prevItem+item]
}, []).map(dir => {
fs.mkdir(dir, err => {
if (err && err.code != 'EEXIST') throw err
// Delete created directory (or skipped) from controlledPath
controlledPaths.splice(controlledPaths.indexOf(dir), 1)
if (controlledPaths.length === 0) {
return callback()
}
})
})
}
// Usage
mkdirRecursive('./photos/recent', () => {
console.log('Directories created succesfully!')
})
Here's my imperative version of mkdirp for nodejs.
function mkdirSyncP(location) {
let normalizedPath = path.normalize(location);
let parsedPathObj = path.parse(normalizedPath);
let curDir = parsedPathObj.root;
let folders = parsedPathObj.dir.split(path.sep);
folders.push(parsedPathObj.base);
for(let part of folders) {
curDir = path.join(curDir, part);
if (!fs.existsSync(curDir)) {
fs.mkdirSync(curDir);
}
}
}
How about this approach :
if (!fs.existsSync(pathToFile)) {
var dirName = "";
var filePathSplit = pathToFile.split('/');
for (var index = 0; index < filePathSplit.length; index++) {
dirName += filePathSplit[index]+'/';
if (!fs.existsSync(dirName))
fs.mkdirSync(dirName);
}
}
This works for relative path.
Based on mouneer's zero-dependencies answer, here's a slightly more beginner friendly Typescript variant, as a module:
import * as fs from 'fs';
import * as path from 'path';
/**
* Recursively creates directories until `targetDir` is valid.
* #param targetDir target directory path to be created recursively.
* #param isRelative is the provided `targetDir` a relative path?
*/
export function mkdirRecursiveSync(targetDir: string, isRelative = false) {
const sep = path.sep;
const initDir = path.isAbsolute(targetDir) ? sep : '';
const baseDir = isRelative ? __dirname : '.';
targetDir.split(sep).reduce((prevDirPath, dirToCreate) => {
const curDirPathToCreate = path.resolve(baseDir, prevDirPath, dirToCreate);
try {
fs.mkdirSync(curDirPathToCreate);
} catch (err) {
if (err.code !== 'EEXIST') {
throw err;
}
// caught EEXIST error if curDirPathToCreate already existed (not a problem for us).
}
return curDirPathToCreate; // becomes prevDirPath on next call to reduce
}, initDir);
}
As clean as this :)
function makedir(fullpath) {
let destination_split = fullpath.replace('/', '\\').split('\\')
let path_builder = destination_split[0]
$.each(destination_split, function (i, path_segment) {
if (i < 1) return true
path_builder += '\\' + path_segment
if (!fs.existsSync(path_builder)) {
fs.mkdirSync(path_builder)
}
})
}
I had issues with the recursive option of fs.mkdir so I made a function that does the following:
Creates a list of all directories, starting with the final target dir and working up to the root parent.
Creates a new list of needed directories for the mkdir function to work
Makes each directory needed, including the final
function createDirectoryIfNotExistsRecursive(dirname) {
return new Promise((resolve, reject) => {
const fs = require('fs');
var slash = '/';
// backward slashes for windows
if(require('os').platform() === 'win32') {
slash = '\\';
}
// initialize directories with final directory
var directories_backwards = [dirname];
var minimize_dir = dirname;
while (minimize_dir = minimize_dir.substring(0, minimize_dir.lastIndexOf(slash))) {
directories_backwards.push(minimize_dir);
}
var directories_needed = [];
//stop on first directory found
for(const d in directories_backwards) {
if(!(fs.existsSync(directories_backwards[d]))) {
directories_needed.push(directories_backwards[d]);
} else {
break;
}
}
//no directories missing
if(!directories_needed.length) {
return resolve();
}
// make all directories in ascending order
var directories_forwards = directories_needed.reverse();
for(const d in directories_forwards) {
fs.mkdirSync(directories_forwards[d]);
}
return resolve();
});
}
I solved the problem this way - similar to other recursive answers but to me this is much easier to understand and read.
const path = require('path');
const fs = require('fs');
function mkdirRecurse(inputPath) {
if (fs.existsSync(inputPath)) {
return;
}
const basePath = path.dirname(inputPath);
if (fs.existsSync(basePath)) {
fs.mkdirSync(inputPath);
}
mkdirRecurse(basePath);
}
Could not find an example to create dir's with the required permissions.
Create Directories async recursively with the permissions you want.
Heres a plain nodejs solution
node v18.12.1
Ubuntu 18
//-----------------------------
const fs = require('fs');
const fsPromises = fs.promises;
const checkDirAccess = async (userDir) => {
try {
await fsPromises.access(userDir, fs.constants.R_OK | fs.constants.W_OK);
console.log(` ${userDir} Dir existss`);
return userDir;
} catch (err) {
if(err.errno = -2)
return await crDir(userDir);
else
throw err;
}
}
const crDir = async (userDir) => {
try {
let newDir = await fsPromises.mkdir(userDir, { recursive: true, mode: 0o700});
// When userDir is created; newDir = undefined;
console.log(` Created new Dir ${newDir}`);
return newDir;
} catch (err) {
throw err;
}
}
const directoryPath = ['uploads/xvc/xvc/xvc/specs', 'uploads/testDir11', 'uploads/xsXa/', 'uploads//xsb//', 'uploads//xsV/'];
const findDir = async() => {
try {
for (const iterator of directoryPath) {
let dirOK = await checkDirAccess(iterator);
if(dirOK)
console.log(`found ${dirOK}`)
}
} catch (error) {
console.error('Error : ', error);
}
}
Exec can be messy on windows. There is a more "nodie" solution. Fundamentally, you have a recursive call to see if a directory exists and dive into the child (if it does exist) or create it. Here is a function that will create the children and call a function when finished:
fs = require('fs');
makedirs = function(path, func) {
var pth = path.replace(/['\\]+/g, '/');
var els = pth.split('/');
var all = "";
(function insertOne() {
var el = els.splice(0, 1)[0];
if (!fs.existsSync(all + el)) {
fs.mkdirSync(all + el);
}
all += el + "/";
if (els.length == 0) {
func();
} else {
insertOne();
}
})();
}
This version works better on Windows than the top answer because it understands both / and path.sep so that forward slashes work on Windows as they should. Supports absolute and relative paths (relative to the process.cwd).
/**
* Creates a folder and if necessary, parent folders also. Returns true
* if any folders were created. Understands both '/' and path.sep as
* path separators. Doesn't try to create folders that already exist,
* which could cause a permissions error. Gracefully handles the race
* condition if two processes are creating a folder. Throws on error.
* #param targetDir Name of folder to create
*/
export function mkdirSyncRecursive(targetDir) {
if (!fs.existsSync(targetDir)) {
for (var i = targetDir.length-2; i >= 0; i--) {
if (targetDir.charAt(i) == '/' || targetDir.charAt(i) == path.sep) {
mkdirSyncRecursive(targetDir.slice(0, i));
break;
}
}
try {
fs.mkdirSync(targetDir);
return true;
} catch (err) {
if (err.code !== 'EEXIST') throw err;
}
}
return false;
}

Node.js check if path is file or directory

I can't seem to get any search results that explain how to do this.
All I want to do is be able to know if a given path is a file or a directory (folder).
The following should tell you. From the docs:
fs.lstatSync(path_string).isDirectory()
Objects returned from fs.stat() and fs.lstat() are of this type.
stats.isFile()
stats.isDirectory()
stats.isBlockDevice()
stats.isCharacterDevice()
stats.isSymbolicLink() // (only valid with fs.lstat())
stats.isFIFO()
stats.isSocket()
NOTE:
The above solution will throw an Error if; for ex, the file or directory doesn't exist.
If you want a true or false approach, try fs.existsSync(dirPath) && fs.lstatSync(dirPath).isDirectory(); as mentioned by Joseph in the comments below.
Update: Node.Js >= 10
We can use the new fs.promises API
const fs = require('fs').promises;
(async() => {
const stat = await fs.lstat('test.txt');
console.log(stat.isFile());
})().catch(console.error)
Any Node.Js version
Here's how you would detect if a path is a file or a directory asynchronously, which is the recommended approach in node.
using fs.lstat
const fs = require("fs");
let path = "/path/to/something";
fs.lstat(path, (err, stats) => {
if(err)
return console.log(err); //Handle error
console.log(`Is file: ${stats.isFile()}`);
console.log(`Is directory: ${stats.isDirectory()}`);
console.log(`Is symbolic link: ${stats.isSymbolicLink()}`);
console.log(`Is FIFO: ${stats.isFIFO()}`);
console.log(`Is socket: ${stats.isSocket()}`);
console.log(`Is character device: ${stats.isCharacterDevice()}`);
console.log(`Is block device: ${stats.isBlockDevice()}`);
});
Note when using the synchronous API:
When using the synchronous form any exceptions are immediately thrown.
You can use try/catch to handle exceptions or allow them to bubble up.
try{
fs.lstatSync("/some/path").isDirectory()
}catch(e){
// Handle error
if(e.code == 'ENOENT'){
//no such file or directory
//do something
}else {
//do something else
}
}
Seriously, question exists five years and no nice facade?
function isDir(path) {
try {
var stat = fs.lstatSync(path);
return stat.isDirectory();
} catch (e) {
// lstatSync throws an error if path doesn't exist
return false;
}
}
Depending on your needs, you can probably rely on node's path module.
You may not be able to hit the filesystem (e.g. the file hasn't been created yet) and tbh you probably want to avoid hitting the filesystem unless you really need the extra validation. If you can make the assumption that what you are checking for follows .<extname> format, just look at the name.
Obviously if you are looking for a file without an extname you will need to hit the filesystem to be sure. But keep it simple until you need more complicated.
const path = require('path');
function isFile(pathItem) {
return !!path.extname(pathItem);
}
If you need this when iterating over a directory (Because that's how I've found this question):
Since Node 10.10+, fs.readdir has a withFileTypes option which makes it return directory entry fs.Dirent instead of strings. Directory entries has a name property, and useful methods such as isDirectory or isFile, so you don't need to call fs.lstat explicitly.
import { promises as fs } from 'fs';
// ./my-dir has two subdirectories: dir-a, and dir-b
const dirEntries = await fs.readdir('./my-dir', { withFileTypes: true });
// let's filter all directories in ./my-dir
const onlyDirs = dirEntries.filter(de => de.isDirectory()).map(de => de.name);
// onlyDirs is now [ 'dir-a', 'dir-b' ]
Here's a function that I use. Nobody is making use of promisify and await/async feature in this post so I thought I would share.
const promisify = require('util').promisify;
const lstat = promisify(require('fs').lstat);
async function isDirectory (path) {
try {
return (await lstat(path)).isDirectory();
}
catch (e) {
return false;
}
}
Note : I don't use require('fs').promises; because it has been experimental for one year now, better not rely on it.
The answers above check if a filesystem contains a path that is a file or directory. But it doesn't identify if a given path alone is a file or directory.
The answer is to identify directory-based paths using "/." like --> "/c/dos/run/." <-- trailing period.
Like a path of a directory or file that has not been written yet. Or a path from a different computer. Or a path where both a file and directory of the same name exists.
// /tmp/
// |- dozen.path
// |- dozen.path/.
// |- eggs.txt
//
// "/tmp/dozen.path" !== "/tmp/dozen.path/"
//
// Very few fs allow this. But still. Don't trust the filesystem alone!
// Converts the non-standard "path-ends-in-slash" to the standard "path-is-identified-by current "." or previous ".." directory symbol.
function tryGetPath(pathItem) {
const isPosix = pathItem.includes("/");
if ((isPosix && pathItem.endsWith("/")) ||
(!isPosix && pathItem.endsWith("\\"))) {
pathItem = pathItem + ".";
}
return pathItem;
}
// If a path ends with a current directory identifier, it is a path! /c/dos/run/. and c:\dos\run\.
function isDirectory(pathItem) {
const isPosix = pathItem.includes("/");
if (pathItem === "." || pathItem ==- "..") {
pathItem = (isPosix ? "./" : ".\\") + pathItem;
}
return (isPosix ? pathItem.endsWith("/.") || pathItem.endsWith("/..") : pathItem.endsWith("\\.") || pathItem.endsWith("\\.."));
}
// If a path is not a directory, and it isn't empty, it must be a file
function isFile(pathItem) {
if (pathItem === "") {
return false;
}
return !isDirectory(pathItem);
}
Node version: v11.10.0 - Feb 2019
Last thought: Why even hit the filesystem?
I could check if a directory or file exists using this:
// This returns if the file is not a directory.
if(fs.lstatSync(dir).isDirectory() == false) return;
// This returns if the folder is not a file.
if(fs.lstatSync(dir).isFile() == false) return;
Function that returns type
I like coffee
type: (uri)-> (fina) ->
fs.lstat uri, (erro,stats) ->
console.log {erro} if erro
fina(
stats.isDirectory() and "directory" or
stats.isFile() and "document" or
stats.isSymbolicLink() and "link" or
stats.isSocket() and "socket" or
stats.isBlockDevice() and "block" or
stats.isCharacterDevice() and "character" or
stats.isFIFO() and "fifo"
)
usage:
dozo.type("<path>") (type) ->
console.log "type is #{type}"

node.js require all files in a folder?

How do I require all files in a folder in node.js?
need something like:
files.forEach(function (v,k){
// require routes
require('./routes/'+v);
}};
When require is given the path of a folder, it'll look for an index.js file in that folder; if there is one, it uses that, and if there isn't, it fails.
It would probably make most sense (if you have control over the folder) to create an index.js file and then assign all the "modules" and then simply require that.
yourfile.js
var routes = require("./routes");
index.js
exports.something = require("./routes/something.js");
exports.others = require("./routes/others.js");
If you don't know the filenames you should write some kind of loader.
Working example of a loader:
var normalizedPath = require("path").join(__dirname, "routes");
require("fs").readdirSync(normalizedPath).forEach(function(file) {
require("./routes/" + file);
});
// Continue application logic here
I recommend using glob to accomplish that task.
var glob = require( 'glob' )
, path = require( 'path' );
glob.sync( './routes/**/*.js' ).forEach( function( file ) {
require( path.resolve( file ) );
});
Base on #tbranyen's solution, I create an index.js file that load arbitrary javascripts under current folder as part of the exports.
// Load `*.js` under current directory as properties
// i.e., `User.js` will become `exports['User']` or `exports.User`
require('fs').readdirSync(__dirname + '/').forEach(function(file) {
if (file.match(/\.js$/) !== null && file !== 'index.js') {
var name = file.replace('.js', '');
exports[name] = require('./' + file);
}
});
Then you can require this directory from any where else.
Another option is to use the package require-dir which let's you do the following. It supports recursion as well.
var requireDir = require('require-dir');
var dir = requireDir('./path/to/dir');
I have a folder /fields full of files with a single class each, ex:
fields/Text.js -> Test class
fields/Checkbox.js -> Checkbox class
Drop this in fields/index.js to export each class:
var collectExports, fs, path,
__hasProp = {}.hasOwnProperty;
fs = require('fs');
path = require('path');
collectExports = function(file) {
var func, include, _results;
if (path.extname(file) === '.js' && file !== 'index.js') {
include = require('./' + file);
_results = [];
for (func in include) {
if (!__hasProp.call(include, func)) continue;
_results.push(exports[func] = include[func]);
}
return _results;
}
};
fs.readdirSync('./fields/').forEach(collectExports);
This makes the modules act more like they would in Python:
var text = new Fields.Text()
var checkbox = new Fields.Checkbox()
One more option is require-dir-all combining features from most popular packages.
Most popular require-dir does not have options to filter the files/dirs and does not have map function (see below), but uses small trick to find module's current path.
Second by popularity require-all has regexp filtering and preprocessing, but lacks relative path, so you need to use __dirname (this has pros and contras) like:
var libs = require('require-all')(__dirname + '/lib');
Mentioned here require-index is quite minimalistic.
With map you may do some preprocessing, like create objects and pass config values (assuming modules below exports constructors):
// Store config for each module in config object properties
// with property names corresponding to module names
var config = {
module1: { value: 'config1' },
module2: { value: 'config2' }
};
// Require all files in modules subdirectory
var modules = require('require-dir-all')(
'modules', // Directory to require
{ // Options
// function to be post-processed over exported object for each require'd module
map: function(reqModule) {
// create new object with corresponding config passed to constructor
reqModule.exports = new reqModule.exports( config[reqModule.name] );
}
}
);
// Now `modules` object holds not exported constructors,
// but objects constructed using values provided in `config`.
I know this question is 5+ years old, and the given answers are good, but I wanted something a bit more powerful for express, so i created the express-map2 package for npm. I was going to name it simply express-map, however the people at yahoo already have a package with that name, so i had to rename my package.
1. basic usage:
app.js (or whatever you call it)
var app = require('express'); // 1. include express
app.set('controllers',__dirname+'/controllers/');// 2. set path to your controllers.
require('express-map2')(app); // 3. patch map() into express
app.map({
'GET /':'test',
'GET /foo':'middleware.foo,test',
'GET /bar':'middleware.bar,test'// seperate your handlers with a comma.
});
controller usage:
//single function
module.exports = function(req,res){
};
//export an object with multiple functions.
module.exports = {
foo: function(req,res){
},
bar: function(req,res){
}
};
2. advanced usage, with prefixes:
app.map('/api/v1/books',{
'GET /': 'books.list', // GET /api/v1/books
'GET /:id': 'books.loadOne', // GET /api/v1/books/5
'DELETE /:id': 'books.delete', // DELETE /api/v1/books/5
'PUT /:id': 'books.update', // PUT /api/v1/books/5
'POST /': 'books.create' // POST /api/v1/books
});
As you can see, this saves a ton of time and makes the routing of your application dead simple to write, maintain, and understand. it supports all of the http verbs that express supports, as well as the special .all() method.
npm package: https://www.npmjs.com/package/express-map2
github repo: https://github.com/r3wt/express-map
Expanding on this glob solution. Do this if you want to import all modules from a directory into index.js and then import that index.js in another part of the application. Note that template literals aren't supported by the highlighting engine used by stackoverflow so the code might look strange here.
const glob = require("glob");
let allOfThem = {};
glob.sync(`${__dirname}/*.js`).forEach((file) => {
/* see note about this in example below */
allOfThem = { ...allOfThem, ...require(file) };
});
module.exports = allOfThem;
Full Example
Directory structure
globExample/example.js
globExample/foobars/index.js
globExample/foobars/unexpected.js
globExample/foobars/barit.js
globExample/foobars/fooit.js
globExample/example.js
const { foo, bar, keepit } = require('./foobars/index');
const longStyle = require('./foobars/index');
console.log(foo()); // foo ran
console.log(bar()); // bar ran
console.log(keepit()); // keepit ran unexpected
console.log(longStyle.foo()); // foo ran
console.log(longStyle.bar()); // bar ran
console.log(longStyle.keepit()); // keepit ran unexpected
globExample/foobars/index.js
const glob = require("glob");
/*
Note the following style also works with multiple exports per file (barit.js example)
but will overwrite if you have 2 exports with the same
name (unexpected.js and barit.js have a keepit function) in the files being imported. As a result, this method is best used when
your exporting one module per file and use the filename to easily identify what is in it.
Also Note: This ignores itself (index.js) by default to prevent infinite loop.
*/
let allOfThem = {};
glob.sync(`${__dirname}/*.js`).forEach((file) => {
allOfThem = { ...allOfThem, ...require(file) };
});
module.exports = allOfThem;
globExample/foobars/unexpected.js
exports.keepit = () => 'keepit ran unexpected';
globExample/foobars/barit.js
exports.bar = () => 'bar run';
exports.keepit = () => 'keepit ran';
globExample/foobars/fooit.js
exports.foo = () => 'foo ran';
From inside project with glob installed, run node example.js
$ node example.js
foo ran
bar run
keepit ran unexpected
foo ran
bar run
keepit ran unexpected
One module that I have been using for this exact use case is require-all.
It recursively requires all files in a given directory and its sub directories as long they don't match the excludeDirs property.
It also allows specifying a file filter and how to derive the keys of the returned hash from the filenames.
Require all files from routes folder and apply as middleware. No external modules needed.
// require
const { readdirSync } = require("fs");
// apply as middleware
readdirSync("./routes").map((r) => app.use("/api", require("./routes/" + r)));
I'm using node modules copy-to module to create a single file to require all the files in our NodeJS-based system.
The code for our utility file looks like this:
/**
* Module dependencies.
*/
var copy = require('copy-to');
copy(require('./module1'))
.and(require('./module2'))
.and(require('./module3'))
.to(module.exports);
In all of the files, most functions are written as exports, like so:
exports.function1 = function () { // function contents };
exports.function2 = function () { // function contents };
exports.function3 = function () { // function contents };
So, then to use any function from a file, you just call:
var utility = require('./utility');
var response = utility.function2(); // or whatever the name of the function is
Can use : https://www.npmjs.com/package/require-file-directory
Require selected files with name only or all files.
No need of absoulute path.
Easy to understand and use.
Using this function you can require a whole dir.
const GetAllModules = ( dirname ) => {
if ( dirname ) {
let dirItems = require( "fs" ).readdirSync( dirname );
return dirItems.reduce( ( acc, value, index ) => {
if ( PATH.extname( value ) == ".js" && value.toLowerCase() != "index.js" ) {
let moduleName = value.replace( /.js/g, '' );
acc[ moduleName ] = require( `${dirname}/${moduleName}` );
}
return acc;
}, {} );
}
}
// calling this function.
let dirModules = GetAllModules(__dirname);
Create an index.js file in your folder with this code :
const fs = require('fs')
const files = fs.readdirSync('./routes')
for (const file of files) {
require('./'+file)
}
And after that you can simply load all the folder with require("./routes")
If you include all files of *.js in directory example ("app/lib/*.js"):
In directory app/lib
example.js:
module.exports = function (example) { }
example-2.js:
module.exports = function (example2) { }
In directory app create index.js
index.js:
module.exports = require('./app/lib');

Resources