Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Object Functions

Functions for working with JSON objects: merging, filtering keys/values, and transformations.

Summary

FunctionSignatureDescription
camel_keysany -> anyRecursively convert all keys to camelCase
chunk_by_sizearray, number -> arraySplit an array into chunks of approximately the specified byte size
compact_deeparray -> arrayRecursively compact arrays, removing nulls at all levels
completenessobject -> numberCalculate percentage of non-null fields (0-100)
data_quality_scoreany -> objectAnalyze data quality and return score with detailed issues
deep_diffobject, object -> objectStructural diff between two objects
deep_equalsany, any -> booleanDeep equality check for any two values
deep_mergeobject, object -> objectRecursively merge objects
defaultsobject, object -> objectAssign default values for missing keys (shallow)
defaults_deepobject, object -> objectRecursively assign default values for missing keys
delete_pathany, string -> anyDelete value at JSON pointer path (immutable)
estimate_sizeany -> numberEstimate the JSON serialization size in bytes
flattenobject -> objectAlias for flatten_keys - flatten nested object with dot notation keys
flatten_arrayany, string? -> objectFlatten nested objects and arrays with dot notation keys (arrays use numeric indices)
flatten_keysobject -> objectFlatten nested object with dot notation keys
from_itemsarray -> objectConvert array of [key, value] pairs to object
getany, string, any? -> anyGet value at dot-separated path with optional default
hasany, string -> booleanCheck if dot-separated path exists
has_same_shapeany, any -> booleanCheck if two values have the same structure (ignoring actual values)
infer_schemaany -> objectInfer a JSON Schema-like type description from a value
invertobject -> objectSwap keys and values
itemsobject -> arrayConvert object to array of [key, value] pairs
kebab_keysany -> anyRecursively convert all keys to kebab-case
leavesany -> arrayGet all leaf values (non-object, non-array)
pascal_keysany -> anyRecursively convert all keys to PascalCase
leaves_with_pathsany -> arrayGet all leaf values with their JSON pointer paths
maskstring, number? -> stringMask a string, showing only the last N characters
omitobject, array -> objectRemove specific keys from object
paginatearray, number, number -> objectGet a page of items from an array with metadata
pathsany -> arrayList all JSON pointer paths in value
paths_toany, string -> arrayFind all dot-notation paths to a key anywhere in structure
pickobject, array -> objectSelect specific keys from object
pluck_deepany, string -> arrayFind all values for a key anywhere in nested structure
redactany, array -> anyRecursively replace values at specified keys with [REDACTED]
redact_keysany, string -> anyRecursively redact keys matching a regex pattern
remove_emptyany -> anyRecursively remove nulls, empty strings, empty arrays, and empty objects
remove_empty_stringsany -> anyRecursively remove empty string values
remove_nullsany -> anyRecursively remove null values
rename_keysobject, object -> objectRename object keys
set_pathany, string, any -> anySet value at JSON pointer path (immutable)
shouty_kebab_keysany -> anyRecursively convert all keys to SHOUTY-KEBAB-CASE
shouty_snake_keysany -> anyRecursively convert all keys to SHOUTY_SNAKE_CASE
snake_keysany -> anyRecursively convert all keys to snake_case
train_keysany -> anyRecursively convert all keys to Train-Case
structural_diffany, any -> objectCompare two values and return their structural differences
templateobject, string -> stringExpand a template string with values from an object using {{key}} syntax
template_strictobject, string -> string | nullExpand a template string, returning null if any variable is missing
truncate_to_sizearray, number -> arrayTruncate an array to fit within approximately the specified byte size
type_consistencyarray -> objectCheck if array elements have consistent types
unflattenobject -> objectAlias for unflatten_keys - restore nested object from dot notation keys
unflatten_keysobject -> objectRestore nested object from dot notation keys
with_entriesobject, string -> objectTransform object entries using an expression (jq parity)

Functions

camel_keys

Recursively convert all keys to camelCase

Signature: any -> any

Examples:

# Snake to camel
camel_keys({user_name: "alice"}) -> {userName: "alice"}
# Kebab to camel
camel_keys({"user-name": "bob"}) -> {userName: "bob"}
# Nested
camel_keys({user_info: {first_name: "x"}}) -> {userInfo: {firstName: "x"}}

CLI Usage:

echo '{}' | jpx 'camel_keys({user_name: "alice"})'

chunk_by_size

Split an array into chunks of approximately the specified byte size

Signature: array, number -> array

Examples:

# All fit in one chunk
chunk_by_size([{a:1}, {b:2}, {c:3}], `100`) -> [[{a:1}, {b:2}, {c:3}]]
# Split into chunks
chunk_by_size([{a:1}, {b:2}], `10`) -> [[{a:1}], [{b:2}]]

CLI Usage:

echo '{}' | jpx 'chunk_by_size([{a:1}, {b:2}, {c:3}], `100`)'

compact_deep

Recursively compact arrays, removing nulls at all levels

Signature: array -> array

Examples:

# Remove nulls from nested arrays
compact_deep([[1, null], [null, 2]]) -> [[1], [2]]
# Deep nesting
compact_deep([[1, null], [null, [2, null]]]) -> [[1], [[2]]]
# Simple array
compact_deep([1, null, 3]) -> [1, 3]

CLI Usage:

echo '{}' | jpx 'compact_deep([[1, null], [null, 2]])'

completeness

Calculate percentage of non-null fields (0-100)

Signature: object -> number

Examples:

# All fields filled
completeness({a: 1, b: 2, c: 3}) -> 100
# One of three filled
completeness({a: 1, b: null, c: null}) -> 33.33
# Nested null counted
completeness({a: 1, b: {c: null}}) -> 66.67
# Empty object is complete
completeness({}) -> 100

CLI Usage:

echo '{}' | jpx 'completeness({a: 1, b: 2, c: 3})'

data_quality_score

Analyze data quality and return score with detailed issues

Signature: any -> object

Examples:

# Perfect data
data_quality_score({a: 1, b: 'hello'}).score -> 100
# Issues detected
data_quality_score({a: null, b: ''}).issues -> [{path: 'a', issue: 'null'}, ...]
# Count null fields
data_quality_score(users).null_count -> 5
# Count type mismatches
data_quality_score(data).type_inconsistencies -> 2

CLI Usage:

echo '{}' | jpx 'data_quality_score({a: 1, b: 'hello'}).score'

deep_diff

Structural diff between two objects

Signature: object, object -> object

Examples:

# Changed value
deep_diff({a: 1}, {a: 2}) -> {added: {}, removed: {}, changed: {a: {from: 1, to: 2}}}
# Added and removed
deep_diff({a: 1}, {b: 2}) -> {added: {b: 2}, removed: {a: 1}, changed: {}}
# No differences
deep_diff({a: 1}, {a: 1}) -> {added: {}, removed: {}, changed: {}}
# New key added
deep_diff({}, {a: 1}) -> {added: {a: 1}, removed: {}, changed: {}}

CLI Usage:

echo '{}' | jpx 'deep_diff({a: 1}, {a: 2})'

deep_equals

Deep equality check for any two values

Signature: any, any -> boolean

Examples:

# Equal nested objects
deep_equals({a: {b: 1}}, {a: {b: 1}}) -> true
# Different values
deep_equals({a: 1}, {a: 2}) -> false
# Equal arrays
deep_equals([1, 2], [1, 2]) -> true
# Order matters
deep_equals([1, 2], [2, 1]) -> false

CLI Usage:

echo '{}' | jpx 'deep_equals({a: {b: 1}}, {a: {b: 1}})'

deep_merge

Recursively merge objects

Signature: object, object -> object

Examples:

# Merge nested objects
deep_merge({a: {b: 1}}, {a: {c: 2}}) -> {a: {b: 1, c: 2}}
# Merge flat objects
deep_merge({a: 1}, {b: 2}) -> {a: 1, b: 2}
# Later values override
deep_merge({a: 1}, {a: 2}) -> {a: 2}
# Merge with empty object
deep_merge({}, {a: 1}) -> {a: 1}

CLI Usage:

echo '{}' | jpx 'deep_merge({a: {b: 1}}, {a: {c: 2}})'

defaults

Assign default values for missing keys (shallow)

Signature: object, object -> object

Examples:

# Keep existing, add missing
defaults({a: 1}, {a: 2, b: 3}) -> {a: 1, b: 3}
# All defaults applied
defaults({}, {a: 1, b: 2}) -> {a: 1, b: 2}
# No defaults needed
defaults({a: 1, b: 2}, {}) -> {a: 1, b: 2}
# Different keys
defaults({x: 1}, {y: 2}) -> {x: 1, y: 2}

CLI Usage:

echo '{}' | jpx 'defaults({a: 1}, {a: 2, b: 3})'

defaults_deep

Recursively assign default values for missing keys

Signature: object, object -> object

Examples:

# Merge nested defaults
defaults_deep({a: {b: 1}}, {a: {c: 2}}) -> {a: {b: 1, c: 2}}
# Keep existing nested
defaults_deep({a: {b: 1}}, {a: {b: 2}}) -> {a: {b: 1}}
# Apply all nested defaults
defaults_deep({}, {a: {b: 1}}) -> {a: {b: 1}}
# Different structure
defaults_deep({x: 1}, {y: {z: 2}}) -> {x: 1, y: {z: 2}}

CLI Usage:

echo '{}' | jpx 'defaults_deep({a: {b: 1}}, {a: {c: 2}})'

delete_path

Delete value at JSON pointer path (immutable)

Signature: any, string -> any

Examples:

# Delete top-level key
delete_path({a: 1, b: 2}, '/b') -> {a: 1}
# Delete nested key
delete_path({a: {b: 1, c: 2}}, '/a/b') -> {a: {c: 2}}
# Delete array element
delete_path([1, 2, 3], '/1') -> [1, 3]
# Path not found
delete_path({a: 1}, '/x') -> {a: 1}

CLI Usage:

echo '{}' | jpx 'delete_path({a: 1, b: 2}, `"/b"`)'

estimate_size

Estimate the JSON serialization size in bytes

Signature: any -> number

Examples:

# String with quotes
estimate_size(`"hello"`) -> 7
# Simple object
estimate_size({a: 1}) -> 7
# Simple array
estimate_size([1, 2, 3]) -> 7

CLI Usage:

echo '{}' | jpx 'estimate_size(`"hello"`)'

flatten

Alias for flatten_keys - flatten nested object with dot notation keys

Signature: object -> object

Examples:

# Simple nested
flatten({a: {b: 1}}) -> {\"a.b\": 1}
# Deep nested
flatten({a: {b: {c: 1}}}) -> {\"a.b.c\": 1}
# Flat object
flatten({a: 1, b: 2}) -> {\"a\": 1, \"b\": 2}

CLI Usage:

echo '{}' | jpx 'flatten({a: {b: 1}})'

flatten_array

Flatten nested objects and arrays with dot notation keys (arrays use numeric indices)

Signature: any, string? -> object

Examples:

# Array with indices
flatten_array({a: [1, 2]}) -> {\"a.0\": 1, \"a.1\": 2}
# Nested object with array
flatten_array({a: {b: [1, 2]}}) -> {\"a.b.0\": 1, \"a.b.1\": 2}
# Array of objects
flatten_array([{a: 1}, {b: 2}]) -> {\"0.a\": 1, \"1.b\": 2}
# Custom separator
flatten_array({a: {b: 1}}, '/') -> {\"a/b\": 1}

CLI Usage:

echo '{}' | jpx 'flatten_array({a: [1, 2]})'

flatten_keys

Flatten nested object with dot notation keys

Signature: object -> object

Examples:

# Simple nested
flatten_keys({a: {b: 1}}) -> {\"a.b\": 1}
# Deep nested
flatten_keys({a: {b: {c: 1}}}) -> {\"a.b.c\": 1}
# Flat object
flatten_keys({a: 1, b: 2}) -> {\"a\": 1, \"b\": 2}
# Mixed nesting
flatten_keys({x: {y: 1}, z: 2}) -> {\"x.y\": 1, \"z\": 2}

CLI Usage:

echo '{}' | jpx 'flatten_keys({a: {b: 1}})'

from_items

Convert array of [key, value] pairs to object

Signature: array -> object

JEP: JEP-013

Examples:

# Single pair
from_items([['a', 1]]) -> {a: 1}
# Multiple pairs
from_items([['a', 1], ['b', 2]]) -> {a: 1, b: 2}
# Empty array
from_items([]) -> {}
# String value
from_items([['x', 'hello']]) -> {x: 'hello'}

CLI Usage:

echo '{}' | jpx 'from_items([['a', 1]])'

get

Get value at dot-separated path with optional default

Signature: any, string, any? -> any

Examples:

# Nested path
get({a: {b: 1}}, 'a.b') -> 1
# Top-level key
get({a: 1}, 'a') -> 1
# Missing with default
get({a: 1}, 'x', 'default') -> 'default'
# Deep path
get({a: {b: {c: 3}}}, 'a.b.c') -> 3

CLI Usage:

echo '{}' | jpx 'get({a: {b: 1}}, `"a.b"`)'

has

Check if dot-separated path exists

Signature: any, string -> boolean

Examples:

# Nested path exists
has({a: {b: 1}}, 'a.b') -> true
# Top-level exists
has({a: 1}, 'a') -> true
# Key missing
has({a: 1}, 'b') -> false
# Nested missing
has({a: {b: 1}}, 'a.c') -> false

CLI Usage:

echo '{}' | jpx 'has({a: {b: 1}}, `"a.b"`)'

has_same_shape

Check if two values have the same structure (ignoring actual values)

Signature: any, any -> boolean

Examples:

# Same keys, different values
has_same_shape({a: 1, b: 2}, {a: 99, b: 100}) -> true
# Different keys
has_same_shape({a: 1}, {a: 1, b: 2}) -> false
# Same length arrays
has_same_shape([1, 2], [3, 4]) -> true

CLI Usage:

echo '{}' | jpx 'has_same_shape({a: 1, b: 2}, {a: 99, b: 100})'

infer_schema

Infer a JSON Schema-like type description from a value

Signature: any -> object

Examples:

# Number type
infer_schema(`42`) -> {type: "number"}
# Object schema
infer_schema({name: "alice", age: 30}) -> {type: "object", properties: {name: {type: "string"}, age: {type: "number"}}}
# Array schema
infer_schema([1, 2, 3]) -> {type: "array", items: {type: "number"}}

CLI Usage:

echo '{}' | jpx 'infer_schema(`42`)'

invert

Swap keys and values

Signature: object -> object

Examples:

# Swap key and value
invert({a: 'x'}) -> {x: 'a'}
# Multiple pairs
invert({a: 'b', c: 'd'}) -> {b: 'a', d: 'c'}
# Empty object
invert({}) -> {}
# Real-world example
invert({name: 'id', value: 'data'}) -> {id: 'name', data: 'value'}

CLI Usage:

echo '{}' | jpx 'invert({a: 'x'})'

items

Convert object to array of [key, value] pairs

Signature: object -> array

JEP: JEP-013

Examples:

# Single key
items({a: 1}) -> [[\"a\", 1]]
# Multiple keys
items({a: 1, b: 2}) -> [[\"a\", 1], [\"b\", 2]]
# Empty object
items({}) -> []
# String value
items({x: 'hello'}) -> [[\"x\", \"hello\"]]

CLI Usage:

echo '{}' | jpx 'items({a: 1})'

kebab_keys

Recursively convert all keys to kebab-case

Signature: any -> any

Examples:

# Camel to kebab
kebab_keys({userName: "alice"}) -> {"user-name": "alice"}
# Snake to kebab
kebab_keys({user_name: "bob"}) -> {"user-name": "bob"}
# Nested
kebab_keys({userInfo: {firstName: "x"}}) -> {"user-info": {"first-name": "x"}}

CLI Usage:

echo '{}' | jpx 'kebab_keys({userName: "alice"})'

leaves

Get all leaf values (non-object, non-array)

Signature: any -> array

Examples:

# Mixed structure
leaves({a: 1, b: [2, 3]}) -> [1, 2, 3]
# Nested object
leaves({a: {b: 1}}) -> [1]
# Flat array
leaves([1, 2, 3]) -> [1, 2, 3]
# Flat object
leaves({a: 1, b: 2}) -> [1, 2]

CLI Usage:

echo '{}' | jpx 'leaves({a: 1, b: [2, 3]})'

pascal_keys

Recursively convert all keys to PascalCase

Signature: any -> any

Examples:

# Camel to pascal
pascal_keys({userName: "alice"}) -> {UserName: "alice"}
# Snake to pascal
pascal_keys({user_name: "bob"}) -> {UserName: "bob"}
# Nested
pascal_keys({userInfo: {firstName: "x"}}) -> {UserInfo: {FirstName: "x"}}

CLI Usage:

echo '{}' | jpx 'pascal_keys({user_name: "alice"})'

leaves_with_paths

Get all leaf values with their JSON pointer paths

Signature: any -> array

Examples:

# Single leaf
leaves_with_paths({a: 1}) -> [{path: \"/a\", value: 1}]
# Nested path
leaves_with_paths({a: {b: 1}}) -> [{path: \"/a/b\", value: 1}]
# Array indices
leaves_with_paths([1, 2]) -> [{path: \"/0\", value: 1}, {path: \"/1\", value: 2}]
# Empty object
leaves_with_paths({}) -> []

CLI Usage:

echo '{}' | jpx 'leaves_with_paths({a: 1})'

mask

Mask a string, showing only the last N characters

Signature: string, number? -> string

Examples:

# Credit card default
mask("4111111111111111") -> "************1111"
# Phone with 3 visible
mask("555-123-4567", `3`) -> "*********567"
# Short string masked
mask("abc") -> "***"

CLI Usage:

echo '{}' | jpx 'mask("4111111111111111")'

omit

Remove specific keys from object

Signature: object, array -> object

Examples:

# Remove one key
omit({a: 1, b: 2}, ['a']) -> {b: 2}
# Remove multiple keys
omit({a: 1, b: 2, c: 3}, ['a', 'c']) -> {b: 2}
# Key not present
omit({a: 1}, ['x']) -> {a: 1}
# Empty removal list
omit({a: 1, b: 2}, []) -> {a: 1, b: 2}

CLI Usage:

echo '{}' | jpx 'omit({a: 1, b: 2}, ['a'])'

paginate

Get a page of items from an array with metadata

Signature: array, number, number -> object

Examples:

# First page
paginate([1,2,3,4,5], `2`, `1`) -> {items: [1,2], page: 1, page_size: 2, total_items: 5, total_pages: 3, has_next: true, has_prev: false}
# Last page
paginate([1,2,3,4,5], `2`, `3`) -> {items: [5], page: 3, page_size: 2, total_items: 5, total_pages: 3, has_next: false, has_prev: true}

CLI Usage:

echo '{}' | jpx 'paginate([1,2,3,4,5], `2`, `1`)'

paths

List all JSON pointer paths in value

Signature: any -> array

Examples:

# Nested object
paths({a: {b: 1}}) -> [\"/a\", \"/a/b\"]
# Flat object
paths({a: 1, b: 2}) -> [\"/a\", \"/b\"]
# Array paths
paths([1, 2]) -> [\"/0\", \"/1\"]
# Empty object
paths({}) -> []

CLI Usage:

echo '{}' | jpx 'paths({a: {b: 1}})'

paths_to

Find all dot-notation paths to a key anywhere in structure

Signature: any, string -> array

Examples:

# Find paths to id
paths_to({a: {id: 1}, b: {id: 2}}, "id") -> ["a.id", "b.id"]
# Array paths
paths_to({users: [{id: 1}]}, "id") -> ["users.0.id"]
# Key not found
paths_to({a: 1}, "x") -> []

CLI Usage:

echo '{}' | jpx 'paths_to({a: {id: 1}, b: {id: 2}}, "id")'

pick

Select specific keys from object

Signature: object, array -> object

Examples:

# Pick one key
pick({a: 1, b: 2}, ['a']) -> {a: 1}
# Pick multiple keys
pick({a: 1, b: 2, c: 3}, ['a', 'c']) -> {a: 1, c: 3}
# Key not present
pick({a: 1}, ['x']) -> {}
# Empty pick list
pick({a: 1, b: 2}, []) -> {}

CLI Usage:

echo '{}' | jpx 'pick({a: 1, b: 2}, ['a'])'

pluck_deep

Find all values for a key anywhere in nested structure

Signature: any, string -> array

Examples:

# Find all ids
pluck_deep({users: [{id: 1}, {id: 2}], meta: {id: 99}}, "id") -> [1, 2, 99]
# Nested values
pluck_deep({a: {b: {c: 1}}, d: {c: 2}}, "c") -> [1, 2]
# Key not found
pluck_deep({a: 1}, "x") -> []

CLI Usage:

echo '{}' | jpx 'pluck_deep({users: [{id: 1}, {id: 2}], meta: {id: 99}}, "id")'

redact

Recursively replace values at specified keys with [REDACTED]

Signature: any, array -> any

Examples:

# Redact password
redact({name: "alice", password: "secret"}, ["password"]) -> {name: "alice", password: "[REDACTED]"}
# Nested redact
redact({user: {name: "bob", ssn: "123"}}, ["ssn"]) -> {user: {name: "bob", ssn: "[REDACTED]"}}
# Array of objects
redact([{token: "abc"}], ["token"]) -> [{token: "[REDACTED]"}]

CLI Usage:

echo '{}' | jpx 'redact({name: "alice", password: "secret"}, ["password"])'

redact_keys

Recursively redact keys matching a regex pattern

Signature: any, string -> any

Examples:

# Multiple patterns
redact_keys({password: "x", api_key: "y"}, "password|api_key") -> {password: "[REDACTED]", api_key: "[REDACTED]"}
# Wildcard pattern
redact_keys({secret_key: "a", secret_token: "b"}, "secret.*") -> {secret_key: "[REDACTED]", secret_token: "[REDACTED]"}

CLI Usage:

echo '{}' | jpx 'redact_keys({password: "x", api_key: "y"}, "password|api_key")'

remove_empty

Recursively remove nulls, empty strings, empty arrays, and empty objects

Signature: any -> any

Examples:

# Remove all empty values
remove_empty({a: \"\", b: [], c: {}, d: null, e: \"hello\"}) -> {e: \"hello\"}
# Nested cleanup
remove_empty({a: {b: \"\", c: 1}}) -> {a: {c: 1}}
# Array cleanup
remove_empty([\"\", \"hello\", [], null]) -> [\"hello\"]

CLI Usage:

echo '{}' | jpx 'remove_empty({a: \"\", b: [], c: {}, d: null, e: \"hello\"})'

remove_empty_strings

Recursively remove empty string values

Signature: any -> any

Examples:

# Remove empty strings
remove_empty_strings({name: \"alice\", bio: \"\"}) -> {name: \"alice\"}
# From arrays
remove_empty_strings([\"hello\", \"\", \"world\"]) -> [\"hello\", \"world\"]
# Nested
remove_empty_strings({a: {b: \"\", c: \"x\"}}) -> {a: {c: \"x\"}}

CLI Usage:

echo '{}' | jpx 'remove_empty_strings({name: \"alice\", bio: \"\"})'

remove_nulls

Recursively remove null values

Signature: any -> any

Examples:

# Remove nulls from object
remove_nulls({a: 1, b: null, c: 2}) -> {a: 1, c: 2}
# Nested nulls
remove_nulls({a: {b: null, c: 1}}) -> {a: {c: 1}}
# Remove from array
remove_nulls([1, null, 2]) -> [1, 2]

CLI Usage:

echo '{}' | jpx 'remove_nulls({a: 1, b: null, c: 2})'

rename_keys

Rename object keys

Signature: object, object -> object

Examples:

# Rename one key
rename_keys({a: 1}, {a: 'b'}) -> {b: 1}
# Rename multiple
rename_keys({a: 1, b: 2}, {a: 'x', b: 'y'}) -> {x: 1, y: 2}
# No matching key
rename_keys({a: 1}, {x: 'y'}) -> {a: 1}
# Real-world rename
rename_keys({old: 'value'}, {old: 'new'}) -> {new: 'value'}

CLI Usage:

echo '{}' | jpx 'rename_keys({a: 1}, {a: 'b'})'

set_path

Set value at JSON pointer path (immutable)

Signature: any, string, any -> any

Examples:

# Add new key
set_path({a: 1}, '/b', `2`) -> {a: 1, b: 2}
# Update existing
set_path({a: 1}, '/a', `2`) -> {a: 2}
# Set nested path
set_path({a: {}}, '/a/b', `1`) -> {a: {b: 1}}
# Update array element
set_path([1, 2], '/1', `5`) -> [1, 5]

CLI Usage:

echo '{}' | jpx 'set_path({a: 1}, `"/b"`, `2`)'

shouty_kebab_keys

Recursively convert all keys to SHOUTY-KEBAB-CASE

Signature: any -> any

Examples:

# Camel to shouty kebab
shouty_kebab_keys({userName: "alice"}) -> {"USER-NAME": "alice"}
# Snake to shouty kebab
shouty_kebab_keys({user_name: "bob"}) -> {"USER-NAME": "bob"}
# Nested
shouty_kebab_keys({userInfo: {firstName: "x"}}) -> {"USER-INFO": {"FIRST-NAME": "x"}}

CLI Usage:

echo '{}' | jpx 'shouty_kebab_keys({user_name: "alice"})'

shouty_snake_keys

Recursively convert all keys to SHOUTY_SNAKE_CASE

Signature: any -> any

Examples:

# Camel to shouty snake
shouty_snake_keys({userName: "alice"}) -> {USER_NAME: "alice"}
# Kebab to shouty snake
shouty_snake_keys({"user-name": "bob"}) -> {USER_NAME: "bob"}
# Nested
shouty_snake_keys({userInfo: {firstName: "x"}}) -> {USER_INFO: {FIRST_NAME: "x"}}

CLI Usage:

echo '{}' | jpx 'shouty_snake_keys({user_name: "alice"})'

snake_keys

Recursively convert all keys to snake_case

Signature: any -> any

Examples:

# Camel to snake
snake_keys({userName: "alice"}) -> {user_name: "alice"}
# Kebab to snake
snake_keys({"user-name": "bob"}) -> {user_name: "bob"}
# Nested
snake_keys({userInfo: {firstName: "x"}}) -> {user_info: {first_name: "x"}}

CLI Usage:

echo '{}' | jpx 'snake_keys({userName: "alice"})'

train_keys

Recursively convert all keys to Train-Case

Signature: any -> any

Examples:

# Camel to train
train_keys({userName: "alice"}) -> {"User-Name": "alice"}
# Snake to train
train_keys({user_name: "bob"}) -> {"User-Name": "bob"}
# Nested
train_keys({userInfo: {firstName: "x"}}) -> {"User-Info": {"First-Name": "x"}}

CLI Usage:

echo '{}' | jpx 'train_keys({user_name: "alice"})'

structural_diff

Compare two values and return their structural differences

Signature: any, any -> object

Examples:

# Changed value
structural_diff({a: 1}, {a: 2}) -> {changed: [{path: "a", from: 1, to: 2}], added: [], removed: []}
# Added key
structural_diff({a: 1}, {a: 1, b: 2}) -> {changed: [], added: [{path: "b", value: 2}], removed: []}
# Removed key
structural_diff({a: 1, b: 2}, {a: 1}) -> {changed: [], added: [], removed: [{path: "b", value: 2}]}

CLI Usage:

echo '{}' | jpx 'structural_diff({a: 1}, {a: 2})'

template

Expand a template string with values from an object using {{key}} syntax

Signature: object, string -> string

Examples:

# Simple substitution
template({name: "Alice"}, `"Hello, {{name}}!"`) -> "Hello, Alice!"
# Nested access
template({user: {name: "Bob"}}, `"Hi {{user.name}}"`) -> "Hi Bob"
# Default value
template({}, `"Hello {{name|World}}"`) -> "Hello World"

CLI Usage:

echo '{}' | jpx 'template({name: "Alice"}, `"Hello, {{name}}!"`)'

template_strict

Expand a template string, returning null if any variable is missing

Signature: object, string -> string | null

Examples:

# All vars present
template_strict({name: "Alice"}, `"Hello, {{name}}!"`) -> "Hello, Alice!"
# Missing variable
template_strict({}, `"Hello, {{name}}!"`) -> null

CLI Usage:

echo '{}' | jpx 'template_strict({name: "Alice"}, `"Hello, {{name}}!"`)'

truncate_to_size

Truncate an array to fit within approximately the specified byte size

Signature: array, number -> array

Examples:

# All fit
truncate_to_size([{a:1}, {b:2}, {c:3}], `100`) -> [{a:1}, {b:2}, {c:3}]
# Truncated
truncate_to_size([{a:1}, {b:2}, {c:3}], `15`) -> [{a:1}, {b:2}]

CLI Usage:

echo '{}' | jpx 'truncate_to_size([{a:1}, {b:2}, {c:3}], `100`)'

type_consistency

Check if array elements have consistent types

Signature: array -> object

Examples:

# Consistent numbers
type_consistency([1, 2, 3]).consistent -> true
# Mixed types
type_consistency([1, 'two', 3]).consistent -> false
# Object field mismatch
type_consistency([{a: 1}, {a: 'x'}]).inconsistencies -> [{field: 'a', ...}]
# Empty array is consistent
type_consistency([]).consistent -> true

CLI Usage:

echo '{}' | jpx 'type_consistency([1, 2, 3]).consistent'

unflatten

Alias for unflatten_keys - restore nested object from dot notation keys

Signature: object -> object

Examples:

# Simple nested
unflatten({\"a.b\": 1}) -> {a: {b: 1}}
# Deep nested
unflatten({\"a.b.c\": 1}) -> {a: {b: {c: 1}}}
# Flat keys
unflatten({\"a\": 1, \"b\": 2}) -> {a: 1, b: 2}

CLI Usage:

echo '{}' | jpx 'unflatten({\"a.b\": 1})'

unflatten_keys

Restore nested object from dot notation keys

Signature: object -> object

Examples:

# Simple nested
unflatten_keys({\"a.b\": 1}) -> {a: {b: 1}}
# Deep nested
unflatten_keys({\"a.b.c\": 1}) -> {a: {b: {c: 1}}}
# Flat keys
unflatten_keys({\"a\": 1, \"b\": 2}) -> {a: 1, b: 2}
# Mixed nesting
unflatten_keys({\"x.y\": 1, \"z\": 2}) -> {x: {y: 1}, z: 2}

CLI Usage:

echo '{}' | jpx 'unflatten_keys({\"a.b\": 1})'

with_entries

Transform object entries using an expression (jq parity)

Signature: object, string -> object

Examples:

# Transform keys and values
with_entries({a: 1, b: 2}, '[upper(@[0]), multiply(@[1], `2`)]') -> {A: 2, B: 4}
# Transform values only
with_entries({a: 1, b: 2}, '[@[0], add(@[1], `10`)]') -> {a: 11, b: 12}
# Filter entries
with_entries({a: 1, b: 2, c: 3}, 'if(@[1] > `1`, @, `null`)') -> {b: 2, c: 3}

CLI Usage:

echo '{}' | jpx 'with_entries({a: 1, b: 2}, `"[upper(@[0]), multiply(@[1], `2`)]"`)'