An open API service indexing awesome lists of open source software.

https://github.com/reedchan7/ls-json

parse ls output to json format.
https://github.com/reedchan7/ls-json

command-line file-listing jc json ls parser

Last synced: 5 months ago
JSON representation

parse ls output to json format.

Awesome Lists containing this project

README

          

# ls-json

[![Zero Dependencies](https://img.shields.io/badge/dependencies-zero-brightgreen.svg)](https://www.npmjs.com/package/ls-json)

A powerful TypeScript library to parse `ls` and `ls -R` output into structured JSON format with advanced querying capabilities.

## ✨ Features

- **🚀 Zero Dependencies** - Pure TypeScript implementation with no external dependencies for maximum compatibility and minimal bundle size
- **📁 Standard ls parsing** - Parse regular `ls -l` output into structured data
- **🔄 Recursive ls parsing** - Parse `ls -R` output with powerful traversal methods
- **⚡ Streaming support** - Process large ls outputs efficiently
- **🎯 Advanced querying** - Find, filter, and traverse directory structures
- **🔍 Depth control** - Limit recursive parsing depth for performance
- **🛡️ Error handling** - Graceful handling of permission denied and malformed entries

## Installation

```bash
npm install ls-json
```

Or using pnpm:

```bash
pnpm add ls-json
```

## Quick Start

### Basic Usage

```typescript
import { parse } from "ls-json";

const lsOutput = `total 160
drwxr-xr-x 12 user staff 384 Sep 19 14:51 .
drwxr-xr-x 9 user staff 288 Sep 19 14:16 ..
drwxr-xr-x 7 user staff 224 Sep 19 14:35 dist
-rw-r--r-- 1 user staff 2640 Sep 19 14:51 index.spec.ts`;

const result = parse(lsOutput);
console.log(JSON.stringify(result, null, 2));
```

Output:

```json
[
{
"filename": "dist",
"flags": "drwxr-xr-x",
"mode": "755",
"type": "directory",
"owner": "user",
"group": "staff",
"size": 224,
"date": "Sep 19 14:35",
"links": 7
},
{
"filename": "index.spec.ts",
"flags": "-rw-r--r--",
"mode": "644",
"type": "file",
"owner": "user",
"group": "staff",
"size": 2640,
"date": "Sep 19 14:51",
"links": 1
}
]
```

### Recursive Directory Parsing

```typescript
import { parse } from "ls-json";

const recursiveOutput = `./src:
total 12
-rw-r--r-- 1 user user 256 Sep 19 14:51 index.ts
drwxr-xr-x 2 user user 4096 Sep 19 14:52 utils

./src/utils:
total 8
-rw-r--r-- 1 user user 128 Sep 19 14:53 helper.ts`;

const result = parse(recursiveOutput, { recursive: true });

// Get all files across all directories
const allFiles = result.getAllEntries();
console.log(allFiles.length); // 3 entries

// Find specific files
const indexFile = result.findEntry((entry) => entry.filename === "index.ts");
console.log(indexFile?.parent); // "./src"

// Filter by file type
const jsFiles = result.filterEntries(
(entry) => entry.filename.endsWith(".ts") && entry.type === "file"
);
console.log(jsFiles.length); // 2 TypeScript files
```

## API Reference

### Core Functions

#### `parse(data: string, options?: ParseOptions)`

The main parsing function that handles both standard and recursive ls output.

**Parameters:**

- `data` - The ls command output string
- `options` - Optional configuration object

**Returns:**

- `LsEntry[]` for standard parsing
- `LsRecursiveOutput` for recursive parsing (when `options.recursive = true`)

#### `parseStreaming(lines: Iterable, options?: ParseOptions)`

Process ls output line by line using a generator for memory efficiency.

### Parse Options

```typescript
interface ParseOptions {
// Parse as recursive ls output (ls -R)
recursive?: boolean;

// Maximum directory depth (0 = root only, undefined = no limit)
depth?: number;

// Include . and .. entries (default: false)
showDotsDir?: boolean;

// Return raw data without processing (default: false)
raw?: boolean;

// Continue on errors (default: false)
ignoreExceptions?: boolean;
}
```

### Recursive Output Methods

When using `recursive: true`, the result object provides powerful traversal methods:

```typescript
// Get all entries from all directories
const allEntries = result.getAllEntries();

// Find first entry matching criteria
const configFile = result.findEntry(
(entry) => entry.filename === "config.json"
);

// Get all entries matching criteria
const largeFiles = result.filterEntries((entry) => entry.size > 1000000);

// Get entries from specific directory
const homeEntries = result.getEntriesByPath("/home/user");

// Get directory tree structure
const tree = result.getDirectoryTree(); // { '/path': [entries...] }

// Process all entries with callback
result.traverse((entry, directory) => {
console.log(`${directory.path}/${entry.filename}`);
});
```

## Advanced Examples

### Depth-Limited Parsing

```typescript
// Only parse root level + 1 level deep
const result = parse(recursiveOutput, {
recursive: true,
depth: 1,
});

// Process shallow structure for better performance
const topLevelDirs = result.filterEntries(
(entry) => entry.type === "directory"
);
```

### File Analysis

```typescript
const result = parse(lsRecursiveOutput, { recursive: true });

// Find the largest file
const largestFile = result
.getAllEntries()
.filter((entry) => entry.type === "file" && typeof entry.size === "number")
.reduce((largest, current) =>
current.size > largest.size ? current : largest
);

// Count files by extension
const extensionCounts = {};
result.traverse((entry) => {
if (entry.type === "file") {
const ext = entry.filename.split(".").pop() || "no-extension";
extensionCounts[ext] = (extensionCounts[ext] || 0) + 1;
}
});

// Find executable files
const executables = result.filterEntries(
(entry) => entry.flags && entry.flags.includes("x") && entry.type === "file"
);
```

### Error Handling

```typescript
const result = parse(lsOutput, {
recursive: true,
ignoreExceptions: true,
});

// Check for parsing errors
if (result.errors) {
console.log("Global errors:", result.errors);
}

// Check directory-specific errors
result.directories.forEach((dir) => {
if (dir.errors) {
console.log(`Errors in ${dir.path}:`, dir.errors);
}
});
```

## Data Structures

### LsEntry

```typescript
interface LsEntry {
filename: string; // File or directory name
flags: string; // Permission string (e.g., "-rwxr-xr-x")
mode: string; // Octal permissions (e.g., "755")
type:
| "file"
| "directory"
| "symlink"
| "block"
| "character"
| "pipe"
| "socket";
owner: string; // Owner username
group: string; // Group name
size: number | string; // Size in bytes or human-readable
date: string; // Modification date
links?: number; // Hard link count
parent?: string; // Parent directory (recursive mode only)
link_to?: string; // Symlink target
epoch?: number; // Unix timestamp (when available)
}
```

## Performance Tips

- Use `depth` parameter to limit recursive parsing depth
- Use `parseStreaming` for very large outputs
- Set `ignoreExceptions: true` for malformed input
- Use specific query methods instead of `getAllEntries()` when possible

## License

[Apache-2.0](./LICENSE)