Quick Start

Get started with @visulima/fs in 5 minutes.

Last updated:

Quick Start

Learn the essentials of @visulima/fs in 5 minutes.

Installation

npm install @visulima/fs

Read and Write JSON

The most common operations - reading and writing JSON files:

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

// Async - Read JSON
const config = await readJson("config.json");
console.log(config);

// Async - Write JSON (creates parent directories automatically)
await writeJson("data/output.json", { result: "success" }, { spaces: 2 });

// Sync versions
const data = readJsonSync("package.json");
writeJsonSync("output.json", data);

Ensure Directories

Create directories safely, including parent directories:

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

// Async - Creates parent directories if they don't exist
await ensureDir("src/components/ui");

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

Check Empty Directory

Determine if a directory is empty:

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

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

// Sync version
const isEmptySync = emptyDirSync("cache");

Walk Directory Trees

Recursively traverse directories:

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

// Async - Walk all files
for await (const entry of walk("src")) {
    console.log(entry.path);
    // entry.isFile, entry.isDirectory, entry.isSymlink available
}

// Sync version
for (const entry of walkSync("src")) {
    if (entry.isFile) {
        console.log("File:", entry.path);
    }
}

Walk with Filters

Filter files by extension or pattern:

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

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

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

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

Find Files Upward

Search for files by walking up parent directories:

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

// Async - Find nearest package.json
const packagePath = await findUp("package.json");
console.log(packagePath); // '/project/package.json'

// Find with multiple possible names
const configPath = await findUp([".config.json", ".config.yml", "config.json"]);

// Sync version
const gitRoot = findUpSync(".git");

Find with Custom Matcher

Use a function to find directories or files:

import { findUp } from "@visulima/fs";
import { basename } from "node:path";

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

// Find file with specific content
const readme = await findUp(async (dir, file) => {
    if (file === "README.md") {
        const content = await readFile(join(dir, file), "utf-8");
        return content.includes("visulima");
    }
    return false;
});

Ensure Files

Create files with their parent directories:

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

// Async - Creates all parent directories
await ensureFile("logs/app/2024/error.log");

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

Safely create symbolic and hard links:

import { ensureLink, ensureSymlink } from "@visulima/fs";

// Hard link
await ensureLink("source.txt", "hardlink.txt");

// Symbolic link
await ensureSymlink("target/directory", "link-to-directory", "dir");
await ensureSymlink("target/file.txt", "link-to-file.txt", "file");

Read and Write YAML

Install the optional yaml dependency first:

npm install yaml

Then use YAML functions:

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

// Async - Read YAML
const config = await readYaml("config.yml");
console.log(config);

// Async - Write YAML
await writeYaml("output.yml", { name: "project", version: "1.0.0" });

// Sync versions
const data = readYamlSync("data.yaml");
writeYamlSync("output.yaml", data);

File Size Utilities

Calculate file sizes with compression support:

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

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

// Get compressed size (gzip)
const compressed = await getCompressedSize("large-file.json", "gzip");
console.log(`${compressed} bytes (gzipped)`);

// Brotli compression
const brotli = await getCompressedSize("bundle.js", "brotli");

EOL Detection

Detect and normalize line endings:

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

// Detect line ending style
const eol = await detectEOL("source.txt");
console.log(eol); // '\n' or '\r\n' or '\r'

// Normalize to Unix line endings
const content = await normalizeEOL("windows-file.txt", "\n");

Common Patterns

Build Script

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

async function build() {
    // Prepare output directory
    await ensureDir("dist");
    await emptyDir("dist");

    // ... build process ...

    // Write build manifest
    await writeJson("dist/manifest.json", {
        version: "1.0.0",
        buildTime: new Date().toISOString(),
    });
}

Find Project Root

import { findUp, readJson } from "@visulima/fs";
import { dirname } from "node:path";

async function getProjectRoot() {
    const packagePath = await findUp("package.json");
    if (!packagePath) {
        throw new Error("Not in a Node.js project");
    }
    return dirname(packagePath);
}

const projectRoot = await getProjectRoot();
const packageJson = await readJson(`${projectRoot}/package.json`);

Process All Source Files

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

async function processSourceFiles() {
    const files: string[] = [];

    for await (const entry of walk("src", {
        extensions: [".ts", ".tsx"],
        skip: ["**/*.test.ts", "**/__tests__/**"],
    })) {
        if (entry.isFile) {
            files.push(entry.path);
            // Process file...
        }
    }

    return files;
}

Configuration Manager

import { readJson, writeJson, findUp } from "@visulima/fs";
import { readYaml, writeYaml } from "@visulima/fs/yaml";

async function loadConfig() {
    // Try JSON first
    const jsonPath = await findUp("config.json");
    if (jsonPath) {
        return { path: jsonPath, data: await readJson(jsonPath) };
    }

    // Fall back to YAML
    const yamlPath = await findUp("config.yml");
    if (yamlPath) {
        return { path: yamlPath, data: await readYaml(yamlPath) };
    }

    throw new Error("No config file found");
}

Sync vs. Async

Every function has both async and sync versions:

// Async (recommended for I/O operations)
const data = await readJson("data.json");
await writeJson("output.json", data);

// Sync (useful in scripts or when needed)
const dataSynce = readJsonSync("data.json");
writeJsonSync("output.json", dataSync);

Recommendation: Use async versions in applications and servers. Use sync versions in build scripts and CLI tools where simplicity is preferred.

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