Catalog npm
PACKAGE EXPLORERView in registry

1ls

npm

1 line script - Lightweight JSON CLI with JavaScript syntax

bunclifxjavascriptjqjson
Versions collected19
Direct dependencies7From release 0.1.15
Last observed20 Oct, 18:32 UTC

README

Current package documentation

1ls

CI codecov npm version License: MIT GitHub

Minimal syntax. Maximum formats.

# full
echo '[1,2,3]' | 1ls '.filter(x => x > 1).map(x => x * 2)'

# shortened
echo '[1,2,3]' | 1ls '.fl(x => x > 1).mp(x => x * 2)'

JavaScript syntax with shortcuts. JSON, YAML, TOML, XML, CSV, INI, ENV, NDJSON. Zero dependencies.

Why 1ls?

  • JavaScript Syntax: Use familiar JavaScript array methods and syntax instead of learning jq's DSL
  • Multi-format: Works with JSON, JSON5, YAML, TOML, XML, INI, CSV, TSV, ENV, NDJSON, JavaScript, TypeScript, and more
  • Fast: Built for speed; no deps, compiled by Bun
  • Intuitive: Property access with dot notation, just like JavaScript
  • Powerful: Full support for array methods, arrow functions, and object operations
  • Shortcuts: Built-in shortcuts for common operations (e.g., .mp for .map)

jq vs fx vs 1ls

Filter and map:

# jq
echo '[{"age":25},{"age":35}]' | jq '[.[] | select(.age > 30) | .age]'

# fx
echo '[{"age":25},{"age":35}]' | fx '.filter(x => x.age > 30).map(x => x.age)'

# 1ls
echo '[{"age":25},{"age":35}]' | 1ls '.filter(x => x.age > 30).map(x => x.age)'
echo '[{"age":25},{"age":35}]' | 1ls '.fl(x => x.age > 30).mp(x => x.age)'

First matching item:

# jq
echo '[{"id":1},{"id":2}]' | jq '[.[] | select(.id == 2)] | first'

# fx
echo '[{"id":1},{"id":2}]' | fx '.find(x => x.id === 2)'

# 1ls
echo '[{"id":1},{"id":2}]' | 1ls '.find(x => x.id === 2)'
echo '[{"id":1},{"id":2}]' | 1ls '.fd(x => x.id === 2)'

Get array length:

# jq
echo '[1,2,3,4,5]' | jq 'length'

# fx
echo '[1,2,3,4,5]' | fx '.length'

# 1ls
echo '[1,2,3,4,5]' | 1ls '.length'
echo '[1,2,3,4,5]' | 1ls '.ln'

YAML input:

# jq - not supported

# fx
echo 'name: Ada' | fx --yaml '.name'

# 1ls (auto-detects format)
echo 'name: Ada' | 1ls '.name'

Convert between forms:

# shorten
1ls --shorten '.filter(x => x > 1).map(x => x * 2)'
# → .fl(x => x > 1).mp(x => x * 2)

# expand
1ls --expand '.fl(x => x > 1).mp(x => x * 2)'
# → .filter(x => x > 1).map(x => x * 2)

Installation

# Using bun (or npm, pnpm, etc)
# works in the commandline or the web
bun add -g 1ls

# Or via binaries. here you get a QuickJs build
# Using Homebrew (macOS/Linux)
brew install yowainwright/tap/1ls
# Using curl
curl -fsSL https://raw.githubusercontent.com/yowainwright/1ls/main/scripts/install.sh | bash

Shell Completions (zsh)

bash <(curl -fsSL https://raw.githubusercontent.com/yowainwright/1ls/main/dist/completions/install-completions.sh)

TODO: bash and fish shell completions are not yet supported.

Quick Start

# Get a property
echo '{"name": "John", "age": 30}' | 1ls '.name'
# Output: "John"

# Array operations
echo '[1, 2, 3, 4, 5]' | 1ls '.filter(x => x > 2)'
# Output: [3, 4, 5]

# Map with arrow functions
echo '[1, 2, 3]' | 1ls '.map(x => x * 2)'
# Output: [2, 4, 6]

# Chain operations
echo '[{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]' | 1ls '.filter(x => x.age > 26).map(x => x.name)'
# Output: ["Alice"]

# Interactive mode - explore JSON with fuzzy search
1ls readFile data.json
# Opens interactive explorer with fuzzy search, arrow key navigation, and live preview

Examples

Interactive Mode

Explore JSON interactively with fuzzy search and build expressions with method discovery:

# Open interactive explorer from a file (automatic when no expression)
1ls readFile data.json

# Works with all supported formats
1ls readFile config.yaml
1ls readFile config.toml

# For remote data, save to a file first
curl https://api.github.com/users/github > /tmp/user.json
1ls readFile /tmp/user.json

# Or use an expression directly (non-interactive)
1ls readFile data.json '.users.filter(x => x.active)'

Mode 1: Path Explorer

Navigate and search JSON paths:

  • Fuzzy search: Type to filter paths (e.g., "user.name" matches .users[0].name, .user.username, etc.)
  • Live preview: See values as you navigate
  • Type information: Shows String, Number, Array, Object, Boolean, or null
  • ↑/↓: Navigate, Enter: Select, Tab: Build expression, Esc/q: Quit

Mode 2: Expression Builder

Build complex expressions with guided method selection:

Workflow:

  1. Navigate to a path in Explorer mode → Press Tab
  2. Type to fuzzy search methods → → to accept
  3. Type to fuzzy search properties → → to complete
  4. Repeat to chain methods
  5. Press Enter to execute

Example Session:

1. Navigate to .users (Array) → Tab
2. Type "fil" → → (accepts .filter(x => ...))
3. Type "act" → → (completes with x.active, back to method selection)
4. Type "map" → → (accepts .map(x => ...))
5. Type "name" → → (completes with x.name)
6. Enter → executes: .users.filter(x => x.active).map(x => x.name)

Undo mistakes:

  • Press ← at any time to undo the last segment
  • Example: .users.filter(x => x.active).map(x => x.name) → ← → .users.filter(x => x.active)

Available Methods by Type:

Array: map, filter, reduce, find, findIndex, some, every, sort, reverse, slice, concat, join, flat, flatMap, length

String: toUpperCase, toLowerCase, trim, trimStart, trimEnd, split, replace, replaceAll, substring, slice, startsWith, endsWith, includes, match, length

Object: {keys}, {values}, {entries}, {length}

Number: toFixed, toString

Keyboard Shortcuts:

  • ↑/↓: Navigate methods/properties
  • → or Tab: Accept/complete method or property (autocomplete-style)
  • ←: Undo last segment (remove to previous dot)
  • Enter: Execute expression
  • Type: Fuzzy search methods/properties
  • Esc: Go back to Explorer / Quit
  • q: Quit (from Explorer)

Use cases:

  • Exploring unfamiliar API responses
  • Building filter/map chains interactively
  • Discovering available methods for each type
  • Learning JavaScript array/string methods
  • Prototyping complex data transformations

Working with JSON

# Access nested properties
echo '{"user": {"name": "John", "posts": [1, 2, 3]}}' | 1ls '.user.name'

# Array indexing (negative indexes supported)
echo '["first", "second", "third"]' | 1ls '.[0]'  # "first"
echo '["first", "second", "third"]' | 1ls '.[-1]' # "third"

# Array slicing
echo '[1, 2, 3, 4, 5]' | 1ls '.[1:3]'  # [2, 3]
echo '[1, 2, 3, 4, 5]' | 1ls '.[:2]'   # [1, 2]
echo '[1, 2, 3, 4, 5]' | 1ls '.[2:]'   # [3, 4, 5]

# Object operations
echo '{"a": 1, "b": 2, "c": 3}' | 1ls '.{keys}'    # ["a", "b", "c"]
echo '{"a": 1, "b": 2, "c": 3}' | 1ls '.{values}'  # [1, 2, 3]
echo '{"a": 1, "b": 2, "c": 3}' | 1ls '.{entries}' # [["a", 1], ["b", 2], ["c", 3]]

Array Methods

# Filter
echo '[1, 2, 3, 4, 5]' | 1ls '.filter(x => x % 2 === 0)'
# Output: [2, 4]

# Map
echo '["hello", "world"]' | 1ls '.map(x => x.toUpperCase())'
# Output: ["HELLO", "WORLD"]

# Reduce
echo '[1, 2, 3, 4]' | 1ls '.reduce((sum, x) => sum + x, 0)'
# Output: 10

# Find
echo '[{"id": 1}, {"id": 2}, {"id": 3}]' | 1ls '.find(x => x.id === 2)'
# Output: {"id": 2}

# Some/Every
echo '[2, 4, 6]' | 1ls '.every(x => x % 2 === 0)'  # true
echo '[1, 2, 3]' | 1ls '.some(x => x > 2)'         # true

# Chaining methods
echo '[1, 2, 3, 4, 5]' | 1ls '.filter(x => x > 2).map(x => x * 2)'
# Output: [6, 8, 10]

Multi-format Support

# YAML input
echo 'name: John
age: 30
city: NYC' | 1ls '.name'
# Output: "John"

# CSV input
echo 'name,age
John,30
Jane,25' | 1ls '.map(x => x.name)'
# Output: ["John", "Jane"]

# ENV file input
echo 'DATABASE_URL=postgres://localhost/db
PORT=3000
DEBUG=true' | 1ls '.PORT'
# Output: 3000

# NDJSON (Newline-Delimited JSON) - great for logs
echo '{"level":"error","msg":"Failed"}
{"level":"info","msg":"Started"}
{"level":"error","msg":"Timeout"}' | 1ls '.filter(x => x.level === "error")'
# Output: [{"level":"error","msg":"Failed"}, {"level":"error","msg":"Timeout"}]

# Specify input format explicitly
cat data.yaml | 1ls --input-format yaml '.users[0].name'
cat data.csv | 1ls --input-format csv '.filter(x => x.age > 25)'
cat app.env | 1ls --input-format env '.DATABASE_URL'
cat logs.ndjson | 1ls --input-format ndjson '.filter(x => x.level === "error")'

Supported Formats:

  • JSON, JSON5 (JSON with comments/trailing commas)
  • YAML, TOML, XML, INI
  • CSV, TSV
  • ENV files (.env)
  • NDJSON (Newline-Delimited JSON for logs)
  • JavaScript, TypeScript (with export default)
  • Plain text, line-by-line

File Operations

# Read from file
1ls readFile data.json '.users.filter(x => x.active)'

# List files
1ls --list . --recursive --ext .json

# Grep files
1ls --grep "TODO" --find . --recursive

# With line numbers
1ls --grep "function" --find ./src --line-numbers

Shortcuts

# Use shortcuts for common operations
echo '[1, 2, 3]' | 1ls '.mp(x => x * 2)'     # Short for .map()
echo '[1, 2, 3]' | 1ls '.flt(x => x > 1)'    # Short for .filter()
echo '["a", "b"]' | 1ls '.jn(",")'           # Short for .join()

# Show all shortcuts
1ls --shortcuts

# Expand shortcuts
1ls --expand ".mp(x => x * 2)"               # Output: .map(x => x * 2)

# Shorten expression
1ls --shorten ".map(x => x * 2)"             # Output: .mp(x => x * 2)

CLI Options

Basic Options

OptionShortDescription
--help-hShow help
--version-vShow version
--interactiveInteractive fuzzy search explorer
--raw-rOutput raw strings, not JSON
--pretty-pPretty print output (default)
--compact-cCompact single-line output
--type-tShow type of result
--slurp-SRead all inputs into an array
--null-input-NUse null as input (for generating data)

Format Options

OptionDescriptionValues
--formatOutput formatjson, yaml, csv, table
--input-format, -ifInput formatjson, yaml, toml, csv, tsv, lines, text

File Operations

OptionShortDescription
readFileRead JSON from file
--list-lList files in directory
--find-fFind files matching pattern
--grep-gSearch for pattern in files
--recursive-RRecursive search
--ignore-case-iCase insensitive search
--line-numbers-nShow line numbers
--extFilter by extensions (comma-separated)
--max-depthMaximum depth for recursive operations

Shortcut Operations

OptionDescription
--shortcutsShow all available shortcuts
--expandExpand shortcuts to full syntax
--shortenConvert to shortcut syntax

API Reference

Property Access

  • .property - Access object property
  • ["property"] - Access property with brackets
  • .[index] - Array index access (negative indexes supported)
  • .[start:end] - Array slice
  • .[] - Array spread

jq-compatible Operators

  • .. - Recursive descent (collect all nested values)
  • .foo? - Optional access (returns null on error instead of failing)
  • .foo ?? default - Null coalescing (provide fallback for null/undefined)
# Recursive descent - get all values from nested structure
echo '{"a": {"b": 1}, "c": [2, 3]}' | 1ls '..'
# Output: [{"a": {"b": 1}, "c": [2, 3]}, {"b": 1}, 1, [2, 3], 2, 3]

# Optional access - safe navigation
echo '{"user": null}' | 1ls '.user?.name'
# Output: null (instead of error)

# Null coalescing - default values
echo '{"name": null}' | 1ls '.name ?? "anonymous"'
# Output: "anonymous"

Object Operations

  • .{keys} - Get object keys
  • .{values} - Get object values
  • .{entries} - Get object entries
  • .{length} - Get length

Array Methods

All standard JavaScript array methods are supported:

  • .map(), .filter(), .reduce()
  • .find(), .findIndex()
  • .some(), .every()
  • .sort(), .reverse()
  • .slice(), .splice()
  • .join(), .split()
  • .includes(), .indexOf()
  • .flat(), .flatMap()

String Methods

  • .toLowerCase(), .toUpperCase()
  • .trim(), .trimStart(), .trimEnd()
  • .replace(), .replaceAll()
  • .startsWith(), .endsWith()
  • .substring(), .charAt()
  • .match(), .split()

Builtin Functions (jq-compatible)

Array Operations:

  • head() / hd() - First element
  • last() / lst() - Last element
  • tail() / tl() - All but first element
  • take(n) / tk(n) - Take first n elements
  • drop(n) / drp(n) - Drop first n elements
  • uniq() / unq() - Remove duplicates
  • flatten() / fltn() - Flatten nested arrays
  • rev() - Reverse array
  • chunk(n) / chnk(n) - Split into chunks of size n
  • compact() / cmpct() - Remove falsy values
  • nth(n) - Get element at index n
  • add() - Sum numbers or concatenate arrays/strings

Object Operations:

  • keys() / ks() - Get object keys
  • vals() - Get object values
  • pick(k1, k2, ...) / pk() - Pick specific keys
  • omit(k1, k2, ...) / omt() - Omit specific keys
  • merge(obj) / mrg() - Shallow merge objects
  • deepMerge(obj) / dMrg() - Deep merge objects
  • fromPairs() / frPrs() - Convert pairs to object
  • toPairs() / toPrs() - Convert object to pairs
  • has(key) / hs() - Check if key exists
  • pluck(key) / plk() - Extract property from array of objects

Grouping & Sorting:

  • groupBy(fn) / grpBy() - Group by key function
  • sortBy(fn) / srtBy() - Sort by key function

Math & Aggregation:

  • sum() - Sum of numbers
  • mean() / avg() - Average of numbers
  • min() - Minimum value
  • max() - Maximum value
  • floor() / flr() - Floor number
  • ceil() / cl() - Ceiling number
  • round() / rnd() - Round number
  • abs() - Absolute value

String Operations:

  • split(sep) / spl() - Split string by separator
  • join(sep) / jn() - Join array with separator
  • startswith(s) / stw() - Check if starts with string
  • endswith(s) / edw() - Check if ends with string
  • ltrimstr(s) / ltrm() - Remove prefix
  • rtrimstr(s) / rtrm() - Remove suffix
  • tostring() / tstr() - Convert to string
  • tonumber() / tnum() - Convert to number

Type & Inspection:

  • type() / typ() - Get value type
  • len() - Get length
  • count() / cnt() - Count items
  • isEmpty() / emp() - Check if empty
  • isNil() / nil() - Check if null/undefined
  • contains(val) / ctns() - Check if contains value

Path Operations:

  • path() / pth() - Get all paths in structure
  • getpath(path) / gpth() - Get value at path
  • setpath(path) / spth() - Set value at path
  • recurse() / rec() - Recursively collect all values

Control Flow:

  • select(fn) / sel() - Filter by predicate (jq-style)
  • empty() - Return nothing
  • error(msg) - Throw error
  • debug() / dbg() - Debug output
  • not() - Boolean negation
  • range(n) / rng() - Generate range [0, n)

Composition:

  • pipe(expr1, expr2, ...) - Apply expressions left-to-right
  • compose(expr1, expr2, ...) - Apply expressions right-to-left
  • id() - Identity function
# Builtin examples
echo '[1, 2, 3, 4, 5]' | 1ls 'head()'      # 1
echo '[1, 2, 3, 4, 5]' | 1ls 'take(3)'     # [1, 2, 3]
echo '[1, 2, 2, 3]' | 1ls 'uniq()'         # [1, 2, 3]
echo '{"a": 1, "b": 2}' | 1ls 'keys()'     # ["a", "b"]
echo '[1, 2, 3]' | 1ls 'sum()'             # 6
echo '"hello"' | 1ls 'split("")'           # ["h", "e", "l", "l", "o"]
echo '42' | 1ls 'type()'                   # "number"
echo 'null' | 1ls 'range(5)'               # [0, 1, 2, 3, 4]

Arrow Functions

Full support for arrow functions in method calls:

.map(x => x * 2)
.filter((item, index) => index > 0)
.reduce((acc, val) => acc + val, 0)

Advanced Examples

Complex Data Processing

# Process API response
curl https://api.github.com/users/github/repos | 1ls \
  '.filter(x => !x.fork)
   .map(x => ({name: x.name, stars: x.stargazers_count}))
   .sort((a, b) => b.stars - a.stars)
   .slice(0, 5)'

# Extract and transform nested data
echo '{
  "users": [
    {"name": "Alice", "posts": [{"title": "Post 1"}, {"title": "Post 2"}]},
    {"name": "Bob", "posts": [{"title": "Post 3"}]}
  ]
}' | 1ls '.users.flatMap(u => u.posts.map(p => ({user: u.name, title: p.title})))'

# Group and aggregate
echo '[
  {"category": "A", "value": 10},
  {"category": "B", "value": 20},
  {"category": "A", "value": 30}
]' | 1ls '.reduce((acc, item) => {
  acc[item.category] = (acc[item.category] || 0) + item.value;
  return acc;
}, {})'

Working with Files

# Find all JSON files and extract specific fields
1ls --list ./data --recursive --ext .json | \
  1ls '.map(f => f.path)' | \
  xargs -I {} sh -c 'echo {} && 1ls readFile {} ".version"'

# Search for TODOs in code
1ls --grep "TODO" --find ./src --recursive --line-numbers

# Process multiple CSV files
for file in *.csv; do
  echo "Processing $file"
  cat "$file" | 1ls --input-format csv '.filter(x => x.status === "active")'
done

Environment Variables

  • NO_COLOR - Disable colored output

Performance

1ls is built with Bun and optimized for speed:

  • Fast JSON parsing and stringification
  • Minimal overhead for expression evaluation
  • Efficient streaming for large files
  • Native binary compilation

Development

# Clone the repository
git clone https://github.com/yowainwright/1ls.git
cd 1ls

# Install dependencies
bun install

# Run tests
bun test

# Build
bun run build

# Build binaries
bun run build:binary:all

Contributing

Contributions are welcome! Please check out the Contributing Guide.

License

MIT © Jeff Wainwright

Comparison with Similar Tools

Feature1lsjqfx
SyntaxJavaScriptDSLJavaScript
ImplementationBun/TSCGo
Learning CurveEasySteepEasy
Multi-format✓ (12+)x✓ (JSON/YAML/TOML)
Auto-detect Format✓xx
Interactive Mode✓x✓
Shortcuts✓xx
Arrow Functions✓x✓
File Operations✓xx
jq Builtins✓✓x
Recursive Descent (..)✓✓x
Null Coalescing (??)✓✓x

Benchmarks

Comparing 1ls with jq and fx across various operations and data sizes.

  • Runs per test: 5
  • Data sizes: 1000, 10000, 100000 records
  • Environment: Docker (debian:bookworm-slim)

Summary

ToolAvg Time (ms)vs 1ls
1ls0.621x
jq103.17166x slower
fx171.61276x slower

1ls is 166x faster than jq and 276x faster than fx on average.

Lower is better. Times in milliseconds (ms).

Basic Operations (ms)

OperationSizejqfx1ls
First element100021.267.790.60
Length100021.266.910.53
Last element100046.027.670.47
First element1000032.2241.500.47
Length1000031.5838.550.47
Last element1000031.1639.530.50
First element100000158.56382.210.64
Length100000188.74351.790.56
Last element100000159.04355.600.52

Filter & Map (ms)

OperationSizejqfx1ls
Filter100020.739.490.47
Map100019.285.890.43
Filter+Map100019.786.280.54
Filter1000047.0265.210.48
Map1000034.3544.060.53
Filter+Map1000037.5244.580.56
Filter100000294.43824.560.68
Map100000208.42395.500.76
Filter+Map100000208.05401.710.54

Aggregation (ms)

OperationSizejqfx1ls
Sum100020.906.210.59
Min100020.667.210.61
Max100020.907.370.57
Sum1000036.9843.530.46
Min1000035.8644.540.54
Max1000036.4444.450.71
Sum100000227.80397.980.65
Min100000205.29396.930.50
Max100000194.16388.880.49

Builtin Functions (ms)

OperationSizejqfx1ls
head()100019.936.550.49
last()100019.885.920.46
take(10)100019.975.620.44
uniq()100020.798.340.42
flatten()100021.539.900.46
head()1000031.3440.230.48
last()1000031.8138.050.54
take(10)1000031.0037.690.46
uniq()1000047.0061.050.48
flatten()1000052.0788.380.62
head()100000171.62353.110.49
last()100000158.29359.100.59
take(10)100000151.69351.130.49
uniq()100000355.20576.730.53
flatten()100000370.08760.430.51

Run bun run test:bench to regenerate benchmarks.

Troubleshooting

Expression Errors

  • Wrap expressions in quotes to prevent shell interpretation
  • Use single quotes for expressions containing dollar signs

Performance

  • For large files, use streaming: cat large.json | 1ls '.property'
  • Use --compact for smaller output size

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 19

Collected releases
VersionPublishedDirect dependenciesOpen version
0.1.15Registry latest14 Apr 20267
0.1.149 Apr 20267
0.1.1322 Dec 20256
0.1.1215 Dec 20256
0.1.1115 Dec 20256
0.1.1015 Dec 20256
0.1.915 Dec 20256
0.1.815 Dec 20256
0.1.715 Dec 20256
0.1.615 Dec 20256
0.1.515 Dec 20256
0.1.415 Dec 20256
0.1.315 Dec 20256
0.1.215 Dec 20256
0.1.115 Dec 20256
0.1.010 Dec 20256
0.0.315 Nov 20254
0.0.226 Oct 20253
0.0.116 Sept 20253

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
yowainwright/1ls

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 18:31 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:6e779354c2bb864ba1ee9fb49875004ea6ff1db5323f961158c06cc65b8bced6