Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

easypathutil

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

easypathutil - npm Package Compare versions

Comparing version 1.2.3 to 1.2.4

2

package.json
{
"name": "easypathutil",
"version": "1.2.3",
"version": "1.2.4",
"description": "Fluent filepaths, made simple.",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -22,3 +22,3 @@ <div align="center">

npm install easypathutil@1.2.3
npm install easypathutil@1.2.4

@@ -35,3 +35,3 @@ ### Two-Part Motivation

• Updated and Lightweight: Package size <7.5kB
• Updated and Lightweight: Package size <10kB

@@ -56,3 +56,3 @@ The tutorial below aims to demonstrate the core functionality of this package.

**Quickstart Usage and Examples**
#### **Quickstart Usage and Examples**

@@ -65,3 +65,3 @@ const Builder = require('easypathutil');

**Fluent Interface Examples (chaining, constructor, .toString, [] vs ())**
#### **Fluent Interface Examples (chaining, constructor, .toString, [] vs ())**

@@ -80,2 +80,3 @@ // Using process.cwd() (root/home/projects/myfolder) as base

Promise: somePromisePackage || global.Promise,
filter: filepath => should_dive_folder(filepath), // This function checks recursive directory dives with a given filter. More below.
});

@@ -92,3 +93,3 @@

**Going backwards and resetting to base path (.$back, .$reset)**
#### **Going backwards and resetting to base path (.$back, .$reset)**

@@ -104,3 +105,3 @@ // Reminder: myjsfile() is '/root/home/projects/myfolder/foo/bar/myjsfile.js'

**Get file contents (.$readfile, .$readfilesync)**
#### **Get file contents (.$readfile, .$readfilesync)**

@@ -122,3 +123,3 @@ const myjsfilebuffer = myjsfile.$readfilesync; // $readfilesync property calls fs.readFileSync

**Easy require (.$require, $require_default)**
#### **Easy require (.$require, $require_default)**

@@ -131,3 +132,3 @@ const imported = myjsfile.$require; // $require property wraps a require() around the target.

**Load JSON without require (.$json)**
#### **Load JSON without require (.$json)**

@@ -137,3 +138,3 @@ const jsonfile = myfolder('jsonfile.json'); // Points to /root/home/projects/myfolder/jsonfile.json

**Read directory recursively, returning an array of absolute paths to files (.$read_dir, .$read_dir_sync)**
#### **Read directory recursively, returning an array of absolute paths to files (.$read_dir, .$read_dir_sync)**

@@ -146,4 +147,102 @@ const filearray = myfolder.$read_dir_sync

**New object shortcut (.$new, .$new_default)**
**Advanced Feature: Recursive Dive Prevention**
Please note that this feature is for more advanced users only who specifically have this need. You may skip down to the next section if you
are reading directories only for files.
Recall back to how to construct the object with options:
const myfolder = new Builder('/root/home/projects/myfolder', {
/* …other options… */
filter: filepath => should_dive_folder(filepath), // This function checks recursive directory dives with a given filter. More below.
});
The filter function can be used to prevent recursive dives. This is useful if you want a list of *folders*. After all, if you wanted to
filter the files returned, the fastest way would be read every file with a basic `myfolder.$readdirsync` and then apply a
`.filter(e => e.endsWith('.mycustomextension')` to the array returned. However, what if you only wanted to read every folder underneath,
say, /src? What if you had a situation where you had folders structured like: `/data/translations/en/data1.json`,
`/data/translations/en/data2.json`, `/data/translations/es/data1.json`, etc, but you only wanted the folder locations, namely
`/data/translations/en/`, `/data/translations/es/`, etc?
**In comes the filter function!**
The filter function filters *out* paths to which it returns true during recursion, and you must apply Array#filter to *keep* what you want.
In our first example, you must create a new object like so:
const array = Builder('/some/path/here' || myfolder() || process.cwd(), {
filter: function filter(path) { return path.endsWith('.ext') && !this.get_stat_sync(path).directory; }
}).$readdirsync
.filter(e => e.endsWith('.ext'));
This will return everything, files and folders, whos name ends with .ext
Optionally, declare the function beforehand:
function filter(path) {
return !path.endsWith('.ext') && this.get_stat_sync(path).directory;
}
const array = Builder(absolutepath, { filter }).$readdirsync
.filter(path => path.endsWith('.ext'));
Don't want the files? You can chain Array#filter in nodejs
const folders_only = array.filter(path => require('fs').statSync(path).isDirectory());
Or just filter once for better performance:
const array = Builder(absolutepath, { filter }).$readdirsync
.filter(path => path.endsWith('.ext') && require('fs').statSync(path).isDirectory());
You may specify also filter parameter as two seperate functions for synchronous and async versions of .$readdir and .$readdirsync
const sync = function filter_sync(path) {
return !path.endsWith('.ext') && this.get_stat_sync(path).directory;
};
const async = async function filter_async(path) {
if (path.endsWith('.ext')) return false; // Think about this line as: if the file or folder we are looking at ends with .ext, stop recursing.
const { directory } = await this.get_stat(path);
return directory; // If directory is true, the path refers to a directory, so keep recursing, in case such files or folders that match the above case reside in subfolders of the one we are currently looking at.
};
const folder = Builder(absolutepath, {
filter: { sync, async },
});
// Use the synchronous version:
const array = folder.$readdirsync.filter(path => path.endsWith('.ext') && require('fs').statSync(path).isDirectory());
// Use the parallel/asynchronous version:
const fs = require('fs');
// Don't forget, you do not need to use .endsWith!
// path.startsWith, regular expressions, and many more also work, as the path string can be freely manipulated
// This applies to the filter functions as well!
const promises = await folder.$readdir.map(path => /\.ext$/.test(path) && new Promise((res, rej) => {
fs.stat(path, (err, stats) => {
if (err) return rej(err);
if (stats.isDirectory()) return res(path);
return res(false);
});
});
const array = await Promise.all(promises).filter(_ => _);
What about your second example with the translations?
function filter(e) { return !e.includes('translations') && this.get_stat_sync(e).directory; };
const array = Builder(process.cwd(), { filter }).subfolder.data.$readdirsync; // Reminder: we can use the same Builder to get to the folder first!
The const array will now contain an array with everything one-level deep into /subfolder/data/translations. In our example, these would be
the two .../en and .../es folders
Notice my usage of the keyword `function` when creating these filter functions. I have not used arrow functions (=> lambdas) because of my
use of "this" (this.get_stat_sync). The filter function is bound to the library's ReadHelper objects, which contain several internal helper
functions to help abstract the directory reading process away from the node fs module. You are free to use arrow functions when this binding
functionality is not of use to you.
Have a more specific use case that you don't believe this covers? Open an issue on this package's github repository (linked below)!
#### **New object shortcut (.$new, .$new_default)**
Before:

@@ -161,3 +260,3 @@

**About .$stat**
#### **File stats (.$stat)**

@@ -187,3 +286,3 @@ // Get file stats synchronously instead of wrapping with fs.statSync with extra function calls

**Existence of a file or folder (in operator, Reflect.has, etc)**
#### **Existence of a file or folder (in operator, Reflect.has, etc)**

@@ -194,3 +293,3 @@ const boolean_exists = 'foldername' in myfolder;

**Version**
#### **Version**

@@ -203,4 +302,10 @@ const version = require('easypathutil').version;

## Changelog
### New in 1.2.4
• Introduced an advanced feature for synchronous and async recursive directory read filtering ("filter" parameter in constructor).
Should you notice anything wrong with this, please do open a reproducible issue or pull request on this package's github repository
(linked below)!
### New in 1.2.3
• Fixed several bugs differentiating between sync and async versions of .$ properties. (i.e. file.$stat and file.$stat.sync)
• Fixed async reading of folders

@@ -224,7 +329,11 @@

#### Enjoy this package?
Consider starring on [github](https://github.com/wzhouwzhou/easypathutil) and checking out some of my other work:
Enjoy this package? Consider starring on [github](https://github.com/wzhouwzhou/easypathutil) and checking out some of my other work:
[Youtube Search API](https://npmjs.com/ytsearcher)
[Urban Dictionary](https://npmjs.com/easyurban)
Need support? Send me an email at wzhouwzhou@gmail.com, or connect with me on Discord at https://discord.gg/jj5FzF7 (William Zhou#0001)
Like what you're seeing? Consider helping to fund my education through https://paypal.me/wzhouwzhou

@@ -10,3 +10,4 @@ const name = exports.name = '$back';

Promise: this._Promise,
readdir_filter: this.readdir_filter,
}, this.parts.slice(0, -1));
};

@@ -10,3 +10,4 @@ const name = exports.name = '$reset';

Promise: this._Promise,
readdir_filter: this.readdir_filter,
});
};

@@ -12,4 +12,6 @@ 'use strict';

Promise = global.Promise,
readdir_filter = null,
filter = null,
} = {}, parts = []) {
if (!(this instanceof PathBuilder)) return new PathBuilder(base, { JSON, path, fs, Promise }, parts);
if (!(this instanceof PathBuilder)) return new PathBuilder(base, { JSON, path, fs, Promise, readdir_filter, filter }, parts);
this.base = base;

@@ -21,3 +23,4 @@ this.parts = parts;

this._Promise = Promise;
this.read_dir = new ReadHelper(this, { fs, path, Promise });
this._readdir_filter = readdir_filter || filter;
this.read_dir = new ReadHelper(this, { fs, path, Promise, readdir_filter, filter });

@@ -30,3 +33,5 @@ // Perform basic checks on potentially user-defined functions

if (typeof Reflect.get(this._path, 'join') !== 'function') throw new Error('Invalid path object, "join" function property missing!');
if (typeof this._readdir_filter !== 'object' && typeof this._readdir_filter !== 'function' && this._readdir_filter !== null) {
throw new Error('Invalid readdir filter, readdir_filter must be a function or null');
}
/*\

@@ -42,3 +47,3 @@ * The hard Promise safety check has been disabled due to the wide variety of Promise libraries out there.

if (!arga) return this._path.join(this.base, ...this.parts);
return new PathBuilder(this.base, { JSON, path, fs, Promise }, [...this.parts, arga.toString()]);
return new PathBuilder(this.base, { JSON, path, fs, Promise, readdir_filter, filter }, [...this.parts, arga.toString()]);
}).bind(this), { has: has.bind(this), get: get.bind(this) });

@@ -45,0 +50,0 @@ return proxy;

@@ -6,3 +6,3 @@ /* eslint consistent-return: 0 */

const ReadHelper = class ReadHelper {
constructor(builder, { fs, path, Promise } = {}) {
constructor(builder, { fs, path, Promise, readdir_filter, filter } = {}) {
this.builder = builder;

@@ -12,2 +12,7 @@ this.fs = fs;

this._Promise = Promise;
this._readdir_filter = readdir_filter || filter;
this.sync_filter = (this._readdir_filter ? this._readdir_filter.sync || this._readdir_filter :
_path => this.get_stat_sync(_path).directory).bind(this);
this.async_filter = (this._readdir_filter ? this._readdir_filter.async || this._readdir_filter.parallel || this._readdir_filter :
_path => this.get_stat(_path).then(stat => stat.directory)).bind(this);
this.load_proxy();

@@ -17,4 +22,4 @@ }

_normalize(sync, filter) {
if (sync === true && !filter) return path => this.get_stat_sync(path).directory;
if (sync === false && !filter) return path => this.get_stat(path).then(stat => stat.directory);
if (sync === true && !filter) return this.sync_filter;
if (sync === false && !filter) return this.async_filter;

@@ -110,32 +115,7 @@ let ref = filter || sync;

const bigInt = !stringprop.toLowerCase().includes('legacy') && !stringprop.toLowerCase().includes('number');
return new Promise((res, rej) => this.fs.stat(path, { bigInt }, (err, stat) => {
if (err) {
if (err.code === 'ENOENT') return res(false);
return rej(err);
}
const isDir = stat.isDirectory(),
isFile = stat.isFile(),
isBigInt = typeof stat.size === 'bigint'; // eslint-disable-line valid-typeof
try {
return res({ ...stat,
isBigInt,
isFile, file: isFile,
isDir, folder: isDir,
directory: isDir,
isFolder: isDir,
isDirectory: isDir,
});
} catch (_err) {
if (_err && _err instanceof SyntaxError) {
return res(Object.assign(stat, {
isBigInt,
file: isFile,
folder: isDir,
directory: isDir,
}));
}
return rej(_err);
}
}));
try {
return new Promise((res, rej) => this.fs.stat(path, { bigInt }, (err, stat) => this.get_stat_cb(err, stat, { res, rej })));
} catch (_node_version_error) {
return new Promise((res, rej) => this.fs.stat(path, (err, stat) => this.get_stat_cb(err, stat, { res, rej })));
}
} catch (err) {

@@ -147,4 +127,36 @@ if (err && err.code === 'ENOENT') return this._Promise.resolve(false);

get_stat_cb(err, stat, { res, rej }) {
if (err) {
if (err.code === 'ENOENT') return res(false);
return rej(err);
}
const isDir = stat.isDirectory(),
isFile = stat.isFile(),
isBigInt = typeof stat.size === 'bigint'; // eslint-disable-line valid-typeof
try {
return res({ ...stat,
isBigInt,
isFile, file: isFile,
isDir, folder: isDir,
directory: isDir,
isFolder: isDir,
isDirectory: isDir,
});
} catch (_err) {
if (_err && _err instanceof SyntaxError) {
return res(Object.assign(stat, {
isBigInt,
file: isFile,
folder: isDir,
directory: isDir,
}));
}
return rej(_err);
}
}
load_proxy() {
const list = this.read_recurse_series(this.path.resolve(__dirname, '../deps/traps'));
const list = this.read_recurse_series(this.path.resolve(__dirname, '../deps/traps'),
e => this.get_stat_sync(e).directory);
this.traps = [];

@@ -151,0 +163,0 @@ for (const { condition, value } of list.map(require)) {

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc