Usage Guide

Complete guide to all file system utilities in @visulima/fs.

Last updated:

Usage Guide

Complete guide to using @visulima/fs file system utilities.

JSON Operations

Read JSON Files

import { readJson, readJsonSync } from "@visulima/fs";

// Async
const config = await readJson("config.json");

// Sync
const packageJson = readJsonSync("package.json");

// With error handling
try {
    const data = await readJson("data.json");
} catch (error) {
    if (error.code === "ENOENT") {
        console.error("File not found");
    }
}

Write JSON Files

import { writeJson, writeJsonSync } from "@visulima/fs";

// Async with formatting
await writeJson("output.json", { key: "value" }, {
    spaces: 2, // 2-space indentation
});

// Sync
writeJsonSync("data.json", { items: [1, 2, 3] });

// Compact (no spaces)
await writeJson("compact.json", data, { spaces: 0 });

// Creates parent directories automatically
await writeJson("deeply/nested/path/file.json", data);

YAML Operations

Requires yaml peer dependency:

npm install yaml

Read YAML Files

import { readYaml, readYamlSync } from "@visulima/fs/yaml";

// Async
const config = await readYaml("config.yml");

// Sync
const data = readYamlSync("data.yaml");

Write YAML Files

import { writeYaml, writeYamlSync } from "@visulima/fs/yaml";

// Async
await writeYaml("output.yml", {
    name: "project",
    version: "1.0.0",
    dependencies: ["package1", "package2"],
});

// Sync
writeYamlSync("config.yaml", configuration);

Directory Walking

Basic Walking

import { walk, walkSync } from "@visulima/fs";

// Async - All entries
for await (const entry of walk("src")) {
    console.log(entry.path);
    console.log("Is file:", entry.isFile);
    console.log("Is directory:", entry.isDirectory);
    console.log("Is symlink:", entry.isSymlink);
}

// Sync
for (const entry of walkSync("src")) {
    console.log(entry.path);
}

Filter by Extension

import { walk } from "@visulima/fs";

// Only TypeScript files
for await (const entry of walk("src", {
    extensions: [".ts", ".tsx"],
})) {
    console.log(entry.path);
}

// Multiple extensions
for await (const entry of walk("src", {
    extensions: [".js", ".jsx", ".ts", ".tsx"],
})) {
    console.log(entry.path);
}

Pattern Matching

import { walk } from "@visulima/fs";

// Include patterns (glob or regex)
for await (const entry of walk("src", {
    match: ["**/components/**/*.tsx", "**/pages/**/*.tsx"],
})) {
    console.log("Component or page:", entry.path);
}

// Exclude patterns
for await (const entry of walk("src", {
    skip: [
        "**/*.test.ts",
        "**/*.spec.ts",
        "**/node_modules/**",
        "**/dist/**",
    ],
})) {
    console.log(entry.path);
}

// Combine include and exclude
for await (const entry of walk(".", {
    match: ["**/*.ts"],
    skip: ["**/node_modules/**", "**/dist/**"],
})) {
    console.log(entry.path);
}

Control Depth

import { walk } from "@visulima/fs";

// Limit depth (1 = only immediate children)
for await (const entry of walk("src", {
    maxDepth: 1,
})) {
    console.log(entry.path);
}

// Only 2 levels deep
for await (const entry of walk("src", {
    maxDepth: 2,
})) {
    console.log(entry.path);
}

Filter Entry Types

import { walk } from "@visulima/fs";

// Only files
for await (const entry of walk("src", {
    includeFiles: true,
    includeDirs: false,
    includeSymlinks: false,
})) {
    console.log("File:", entry.path);
}

// Only directories
for await (const entry of walk("src", {
    includeFiles: false,
    includeDirs: true,
})) {
    console.log("Directory:", entry.path);
}
import { walk } from "@visulima/fs";

// Follow symbolic links
for await (const entry of walk("src", {
    followSymlinks: true,
})) {
    console.log(entry.path);
}

// Don't follow symlinks (default)
for await (const entry of walk("src", {
    followSymlinks: false,
    includeSymlinks: true, // But include them in results
})) {
    if (entry.isSymlink) {
        console.log("Symlink:", entry.path);
    }
}

Finding Files Upward

Find Single File

import { findUp, findUpSync } from "@visulima/fs";

// Async - Find nearest package.json
const packagePath = await findUp("package.json");
if (packagePath) {
    console.log("Found at:", packagePath);
}

// Sync
const gitPath = findUpSync(".git");

Find Multiple Possible Files

import { findUp } from "@visulima/fs";

// Try multiple filenames in order
const configPath = await findUp([
    ".config.json",
    ".config.yml",
    "config.json",
    "config.yml",
]);

Find with Custom Matcher

import { findUp } from "@visulima/fs";
import { basename, join } from "node:path";
import { readFile } from "node:fs/promises";

// Find by directory name
const nodeModules = await findUp((dir) => {
    return basename(dir) === "node_modules";
});

// Find by file content
const packageWithName = await findUp(async (dir, file) => {
    if (file === "package.json") {
        const content = await readFile(join(dir, file), "utf-8");
        const pkg = JSON.parse(content);
        return pkg.name === "my-package";
    }
    return false;
});

Custom Search Options

import { findUp } from "@visulima/fs";

// Start from specific directory
const found = await findUp("config.json", {
    cwd: "/specific/start/directory",
});

// Stop at specific directory
const foundWithStop = await findUp("file.txt", {
    stopAt: "/home/user", // Don't search above this
});

// Search up to root
const foundAtRoot = await findUp(".git", {
    type: "directory",
});

Ensuring Files and Directories

Ensure Directory

Creates directory and all parent directories:

import { ensureDir, ensureDirSync } from "@visulima/fs";

// Async
await ensureDir("src/components/ui/buttons");

// Sync
ensureDirSync("dist/assets/images/thumbnails");

// Returns existing directory path if it already exists
const dirPath = await ensureDir("existing/directory");

Ensure File

Creates file and all parent directories:

import { ensureFile, ensureFileSync } from "@visulima/fs";

// Async
await ensureFile("logs/app/2024/01/error.log");

// Sync
ensureFileSync("cache/temp/data.txt");

// Creates empty file if it doesn't exist
// Does nothing if file already exists
await ensureFile("path/to/new/file.txt");
import { ensureLink, ensureLinkSync } from "@visulima/fs";

// Async - Create hard link
await ensureLink("source.txt", "hardlink.txt");

// Sync
ensureLinkSync("original.dat", "link.dat");
import { ensureSymlink, ensureSymlinkSync } from "@visulima/fs";

// File symlink
await ensureSymlink("target/file.txt", "link-to-file.txt", "file");

// Directory symlink
await ensureSymlink("target/directory", "link-to-dir", "dir");

// Sync versions
ensureSymlinkSync("source.txt", "link.txt", "file");

Directory Utilities

Check Empty Directory

import { emptyDir, emptyDirSync } from "@visulima/fs";

// Async
const isEmpty = await emptyDir("temp");
if (isEmpty) {
    console.log("Directory is empty or doesn't exist");
}

// Sync
if (emptyDirSync("cache")) {
    console.log("Cache is empty");
}

File Size Utilities

Get File Size

import { getFileSize, getFileSizeSync } from "@visulima/fs/size";

// Async
const bytes = await getFileSize("large-file.json");
console.log(`File size: ${bytes} bytes`);

// Sync
const size = getFileSizeSync("image.png");
console.log(`Size: ${(size / 1024).toFixed(2)} KB`);

Get Compressed Size

Calculate file size after compression:

import { getCompressedSize, getCompressedSizeSync } from "@visulima/fs/size";

// Gzip compression
const gzipSize = await getCompressedSize("bundle.js", "gzip");
console.log(`Gzipped: ${gzipSize} bytes`);

// Brotli compression
const brotliSize = await getCompressedSize("bundle.js", "brotli");
console.log(`Brotli: ${brotliSize} bytes`);

// Sync versions
const sizeGzip = getCompressedSizeSync("file.txt", "gzip");
const sizeBrotli = getCompressedSizeSync("file.txt", "brotli");

// Compare sizes
const original = await getFileSize("bundle.js");
const gzip = await getCompressedSize("bundle.js", "gzip");
const brotli = await getCompressedSize("bundle.js", "brotli");

console.log(`Original: ${original} bytes`);
console.log(`Gzip: ${gzip} bytes (${((gzip / original) * 100).toFixed(1)}%)`);
console.log(`Brotli: ${brotli} bytes (${((brotli / original) * 100).toFixed(1)}%)`);

EOL (End of Line) Utilities

Detect Line Endings

import { detectEOL, detectEOLSync } from "@visulima/fs/eol";

// Async
const eol = await detectEOL("source.txt");
console.log(eol); // '\n' (Unix), '\r\n' (Windows), or '\r' (old Mac)

// Sync
const lineEnding = detectEOLSync("file.txt");
if (lineEnding === "\r\n") {
    console.log("Windows line endings");
} else if (lineEnding === "\n") {
    console.log("Unix line endings");
}

Normalize Line Endings

import { normalizeEOL, normalizeEOLSync } from "@visulima/fs/eol";

// Async - Convert to Unix line endings
await normalizeEOL("source.txt", "\n");

// Convert to Windows line endings
await normalizeEOL("source.txt", "\r\n");

// Sync version
normalizeEOLSync("file.txt", "\n");

Next Steps

Support

Contribute to our work and keep us going

Community is the heart of open source. The success of our packages wouldn't be possible without the incredible contributions of users, testers, and developers who collaborate with us every day.Want to get involved? Here are some tips on how you can make a meaningful impact on our open source projects.

Ready to help us out?

Be sure to check out the package's contribution guidelines first. They'll walk you through the process on how to properly submit an issue or pull request to our repositories.

Submit a pull request

Found something to improve? Fork the repo, make your changes, and open a PR. We review every contribution and provide feedback to help you get merged.

Good first issues

Simple issues suited for people new to open source development, and often a good place to start working on a package.
View good first issues