FSTB stands for FileSystem ToolBox. This library aims to make it easier to interact with the file system in Node.js.
For install FSTB:
npm install fstb --save
Most basics way to use FSTB power start from create path to filesystem object using the FSPath function. It can be chained with any key name wich act as path segment.
Example:
FSPath(__dirname).node_modules //work as path.join(__dirname, "node_modules")
FSPath(__dirname)["package.json"] //work as path.join(__dirname, "package.json")
FSPath(__dirname)["node_modules"]["fstb"]["package.json"]
In many cases, you may need to work with special operating system directories. To do this, you can use a number of shortcuts that will make your code shorter and clearer.
cwd
is shortcut toFSPath(process.cwd())
dirname
is shortcut toFSPath(__dirname)
home
is shortcut toFSPath(os.homedir())
tmp
is shortcut toFSPath(os.tmpdir())
You often need to get different paths for the development, staging, and production environment.
In such cases, it is common practice to store these paths in environment variables.
To support this use case, FSTB provides the envPath
method.
const { envPath } = require('fstb');
const { join } = require('path');
//Throws if no APP_DATA_DIR environment variable was found
const data_path = envPath("APP_DATA_DIR")
////If no APP_DATA_DIR environment variable was found, it fallback to assets/images in work directory
const images_path = envPath("APP_IMAGES_PATH", join(process.cwd(), "assets/images"))
Sometimes you need to work with temporary files in your project.
Good practice for this case to do it in OS default temp dir.
mkdtemp
method creates temporary subdir with random name in OS temp directory.
const { mkdtemp } = require('fstb');
//creates temporary directory with 'fstb-' prefix
mkdtemp("fstb-").then(tempdir => {
console.log(tempdir.path)
//Output: C:\Users\user\AppData\Local\Temp\fstb-YBqC2b - for Windows
})
This is a tricky point to understand about the essence of FSPath. On the one hand, FSPath accepts a property or key with any name and returns a new FSPath, the closure of which contains the specified path. On the other hand, since it is a function, its call returns an object of type FSDirent. Thanks to this, we can construct a path by adding segment after segment, and when the path formation is complete, we just need to call the resulting function to continue working with all features of the FSTB library.
Example:
const root = FSPath(__dirname); //Now root is function which closure __dirname path
//We can chain root path by any property or key
const node_modules_path = root.node_modules
const package_json_path = root["package.json"]
//node_modules_path and package_json_path is function and we can call it.
const node_modules_dir = node_modules_path().asDir() //now node_modules_dir is FSDir object for node_modules directory
const package_json_file = package_json_path().asFile() //and package_json_file is FSFile object for package.json file
//Before this point we didn't interact with filesystem. And now we do.
//iterate node_module subdirs and print names to console
node_modules_dir.subdirs().forEach(async subdir => console.log(subdir.name))
//print package.json content to console
package_json_file.read.txt().then(content => console.log(content))
All specific methods for interacts with directories contains in FSDir
class.
Here is table of it:
Method name | Description |
---|---|
dirents() |
Iterates thru all directory contents |
files() |
Iterates thru files in directory |
subdirs(recursive: boolean = false) |
Iterates thru subdirectories in directory. Can iterates all subdirectories tree by set to true optional parameter. |
rmdir() |
Removes directory if its empty |
mkdir(recursive: boolean = false) |
Creates directory. If recursive is true it can create all parent dirs wich not exists. |
isExists() |
Check if directory exist |
totalSize() |
Calculates the size of the entire directory content in bytes |
rimraf() |
Removes directory with all content |
copyTo(targetDir: FSDir) |
Copy directory with all content into target directory |
Also FSDir
has some useful fields:
Field name | Description |
---|---|
path |
The full path for this directory |
name |
Name of this directory |
fspath |
FSPath function to construct child pathes from this directory |
const { cwd, mkdtemp } = require('fstb');
(async function() {
// Create temp dir
const tempdir = await mkdtemp('FSTB_Example_');
// Get node_modules directory
const node_modules = cwd.node_modules().asDir();
console.log('Copy node_modules to temporary directory');
const temp_node_modules = await node_modules.copyTo(tempdir);
console.log('Calc node_modules size');
console.log('node_modules size = ', await node_modules.totalSize());
console.log('Calc temporary node_modules size');
console.log('temporary node_modules size = ', await temp_node_modules.totalSize());
console.log('Remove temporary node_modules directory');
await tempdir.rimraf();
})();
const { cwd } = require('./dist/index');
(async function() {
const node_modules = cwd.node_modules().asDir();
const calcJSSize = async dir =>
await dir
.files()
.filter(async file => file.name.toLowerCase().endsWith('.js'))
.reduce(async (acc, file) => acc + (await file.stat()).size, 0);
console.log('.js files size = ', await node_modules.subdirs(true).reduce(async (acc, dir) => acc + (await calcJSSize(dir)), 0));
})();
import { FSPath, cwd } from 'fstb';
cwd.node_modules().asDir().subdirs(async dir=>console.log(dir.name))
const objectToWrite = {
test: 'test',
test1: 123,
};
//constructs path to file and get it as FSFile object
const file1 = cwd.test.testfiles.dir1['file1.json']().asFile();
//serialize object as json and save in to file1.json
await file1.write.json(objectToWrite);
//read json object from file1.json
const readedObject = await file1.read.json();
const stat = await cwd.test.testfiles['2.json']().asFile().stat()
It's complex example shows complex use case for FSTB.
const { cwd } = require('fstb');
cwd
.node_modules()
.asDir()
.subdirs(true) //true for recursive scan all subfolders
.map(async dir => dir.fspath['package.json']().asFile())
.filter(async package_json => await package_json.isReadable())
.map(async package_json => await package_json.read.json())
.forEach(async content => console.log(`${content.name}@${content.version}`));
Results: