CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-path-scurry

Extremely high performant utility for building tools that read the file system, minimizing filesystem and path string munging operations to the greatest degree possible

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

directory-operations.mddocs/

Directory Operations

High-performance directory reading operations with intelligent caching, multiple output formats, and error handling. All operations cache results to minimize filesystem calls on subsequent accesses.

Capabilities

Asynchronous Directory Reading

Read directory contents asynchronously with configurable output formats.

/**
 * Read directory contents asynchronously
 * @param entry - Directory to read (defaults to current working directory)
 * @param opts - Options controlling output format
 * @returns Promise resolving to array of Path objects or strings
 */
readdir(): Promise<PathBase[]>;
readdir(opts: { withFileTypes: true }): Promise<PathBase[]>;
readdir(opts: { withFileTypes: false }): Promise<string[]>;
readdir(opts: { withFileTypes: boolean }): Promise<PathBase[] | string[]>;
readdir(entry: PathBase | string): Promise<PathBase[]>;
readdir(entry: PathBase | string, opts: { withFileTypes: true }): Promise<PathBase[]>;
readdir(entry: PathBase | string, opts: { withFileTypes: false }): Promise<string[]>;
readdir(entry: PathBase | string, opts: { withFileTypes: boolean }): Promise<PathBase[] | string[]>;

Usage Examples:

import { PathScurry } from "path-scurry";

const pw = new PathScurry();

// Default: returns Path objects
const entries1 = await pw.readdir();
for (const entry of entries1) {
  console.log(`${entry.name}: ${entry.getType()}`);
}

// Return string names only
const names = await pw.readdir({ withFileTypes: false });
console.log("Files:", names);

// Read specific directory
const srcFiles = await pw.readdir("./src");
const textFiles = srcFiles.filter(entry => 
  entry.isFile() && entry.name.endsWith(".txt")
);

// Mixed usage with Path objects
const configDir = await pw.readdir("./config", { withFileTypes: true });
for (const entry of configDir) {
  if (entry.isFile()) {
    console.log(`Config file: ${entry.fullpath()}`);
  }
}

Synchronous Directory Reading

Read directory contents synchronously with the same API as async version.

/**
 * Read directory contents synchronously
 * @param entry - Directory to read (defaults to current working directory)
 * @param opts - Options controlling output format
 * @returns Array of Path objects or strings
 */
readdirSync(): PathBase[];
readdirSync(opts: { withFileTypes: true }): PathBase[];
readdirSync(opts: { withFileTypes: false }): string[];
readdirSync(opts: { withFileTypes: boolean }): PathBase[] | string[];
readdirSync(entry: PathBase | string): PathBase[];
readdirSync(entry: PathBase | string, opts: { withFileTypes: true }): PathBase[];
readdirSync(entry: PathBase | string, opts: { withFileTypes: false }): string[];
readdirSync(entry: PathBase | string, opts: { withFileTypes: boolean }): PathBase[] | string[];

Usage Examples:

const pw = new PathScurry("/project");

// Synchronous directory reading
const entries = pw.readdirSync("src");
const jsFiles = entries.filter(entry => 
  entry.isFile() && entry.name.endsWith(".js")
);

// Get just filenames
const fileNames = pw.readdirSync("dist", { withFileTypes: false });
console.log("Built files:", fileNames);

// Process directory structure
function listDirectory(path: string, level = 0) {
  const indent = "  ".repeat(level);
  const entries = pw.readdirSync(path);
  
  for (const entry of entries) {
    console.log(`${indent}${entry.name} (${entry.getType()})`);
    if (entry.isDirectory()) {
      listDirectory(entry.fullpath(), level + 1);
    }
  }
}

listDirectory("./");

Path Object Directory Methods

Directory operations available directly on Path objects.

/**
 * Read directory contents for this Path object
 * @returns Promise resolving to array of child Path objects
 */
readdir(): Promise<PathBase[]>;

/**
 * Read directory contents synchronously for this Path object
 * @returns Array of child Path objects
 */
readdirSync(): PathBase[];

/**
 * Node-style callback interface for directory reading
 * @param cb - Callback function receiving (error, entries)
 * @param allowZalgo - Whether to allow immediate callback execution
 */
readdirCB(
  cb: (er: NodeJS.ErrnoException | null, entries: PathBase[]) => any,
  allowZalgo?: boolean
): void;

/**
 * Check if this path can be read as a directory
 * @returns True if path is likely readable as directory
 */
canReaddir(): boolean;

/**
 * Check if readdir has been successfully called on this path
 * @returns True if directory contents are cached
 */
calledReaddir(): boolean;

/**
 * Get cached directory contents without filesystem access
 * @returns Array of cached child entries (may be empty if not cached)
 */
readdirCached(): PathBase[];

Usage Examples:

const pw = new PathScurry();
const srcDir = pw.cwd.resolve("src");

// Direct Path object usage
if (srcDir.canReaddir()) {
  const files = await srcDir.readdir();
  console.log(`Found ${files.length} entries in src/`);
}

// Callback-style reading
srcDir.readdirCB((err, entries) => {
  if (err) {
    console.error("Failed to read directory:", err);
    return;
  }
  
  console.log("Directory contents:", entries.map(e => e.name));
});

// Check cache status
if (srcDir.calledReaddir()) {
  const cached = srcDir.readdirCached();
  console.log("Cached entries:", cached.length);
} else {
  console.log("Directory not yet read");
}

Error Handling

Directory operations handle errors gracefully and return empty arrays when paths cannot be read.

Error Scenarios:

  • Non-existent directories: Return empty array instead of throwing
  • Permission denied: Return empty array, path marked accordingly
  • Not a directory: Return empty array for files or other entry types
  • Filesystem errors: Return empty array, error information cached

Example:

const pw = new PathScurry();

// These all return empty arrays instead of throwing
const missing = await pw.readdir("./does-not-exist");        // []
const file = await pw.readdir("./package.json");             // []
const restricted = await pw.readdir("/root/.ssh");           // [] (if no permission)

// Check path status
const path = pw.cwd.resolve("./some-path");
if (path.isENOENT()) {
  console.log("Path does not exist");
} else if (!path.canReaddir()) {
  console.log("Path cannot be read as directory");
}

Performance Considerations

  • First access: Directory contents loaded from filesystem
  • Subsequent access: Results served from cache (much faster)
  • Cache invalidation: Manual invalidation not supported - assume filesystem is stable
  • Memory usage: Controlled by childrenCacheSize option (default: 16384 entries)
  • Large directories: Consider using streaming or iterator interfaces for directories with many entries

Install with Tessl CLI

npx tessl i tessl/npm-path-scurry

docs

directory-operations.md

directory-walking.md

filesystem-metadata.md

index.md

path-objects.md

path-resolution.md

tile.json