Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/chrisdone/jl
Functional sed for JSON
https://github.com/chrisdone/jl
command-line command-line-tool haskell json
Last synced: 3 months ago
JSON representation
Functional sed for JSON
- Host: GitHub
- URL: https://github.com/chrisdone/jl
- Owner: chrisdone-archive
- License: bsd-3-clause
- Archived: true
- Created: 2017-07-15T21:03:09.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2022-05-17T07:42:09.000Z (over 2 years ago)
- Last Synced: 2024-05-31T19:44:56.822Z (5 months ago)
- Topics: command-line, command-line-tool, haskell, json
- Language: Haskell
- Homepage:
- Size: 92.8 KB
- Stars: 474
- Watchers: 9
- Forks: 20
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# jl [![Build Status](https://travis-ci.org/chrisdone/jl.svg)](https://travis-ci.org/chrisdone/jl)
jl ("JSON lambda") is a tiny functional language for querying and
manipulating JSON.Example:
``` haskell
$ jl 'map $ \o -> { sha: o.sha, ps: map _.sha o.parents }' x.json
[{"sha":"7b81a836c31500e685d043729259affa8b670a87","ps":["c538237f4e4c381d35f1c15497c...
```## Installing
Binary releases for Linux and OS X are available [here](https://github.com/chrisdone/jl/releases).
Builds on Windows (see [AppVeyor status](https://ci.appveyor.com/project/chrisdone/jl)), haven't added Windows
binaries to the releases yet.Installing from source:
1. Get [stack](https://haskell-lang.org/get-started)
2. Run `stack install` in the repository directory.
3. Add `~/.local/bin/` to your `PATH`.## Core syntax
Literals:
123, 4.5, -6, "hi", null, true, false
Lambdas:
\x -> y
Function application
get "f" o
Arithmetic:
x * (4 + 3)
Objects:
{foo: 123, bar: 34.3, "a:b": "hi"}
Arrays:
[1, 4 * 5, id 5]
Conditionals:
if x then y else z
Short-hand for fields:
o.f is sugar for get "f" o
_.f is sugar for (\o -> get "f" o)For arrays:
_[0] is sugar for (\o -> get 0 o)
Or objects:
_[k] is sugar for (\o -> get k o)
_["foo"] is sugar for (\o -> get "foo" o)Function composition:
a | b | c is sugar for `\x -> c (b (a x))`
## Mini tutorial
You do everything with usual functional programming functions.
Returning the same thing, aka identity. That's normal in functional
programming:``` haskell
jl 'id'
```A sequence of JSON strings will be read in and processed individually:
E.g.
``` haskell
$ cat x.json | jl id
{"a":1}
{"a":2}
{"a":3}
{"a":4}
```If you want to read the input in as an array, use `--array`:
``` haskell
$ cat x.json | jl --array 'map _.a'
[1,2,3,4]
```After processing, sometimes you want to print each element of the
array out line by line, for that use `--lines`:``` haskell
$ cat x.json | jl --array --lines 'map _.a'
1
2
3
4
```Taking the first element of something, using syntax that looks like
regular array access. The `_` is a short-hand so that you don't need a
lambda:``` haskell
jl '_[0]'
```If you want to get what keys are available, you can run:
``` haskell
jl 'map keys | _[0]'
["sha","committer","url","comments_url","parents","author","html_url","commit"]
```Taking the first element and then creating a record of some parts of it:
``` haskell
jl '_[0] | \o -> {msg: o.commit.message, n: o.commit.committer.name}'
```Note the use of `|` to compose functions. Just like in the shell.
Applying a function to all elements in an array:
``` haskell
jl 'map _.commit.committer.name'
```Note how you can nest property access easily.
Applying something more detailed, by constructing a record of our own
``` haskell
jl 'map $ \o -> {msg: o.commit.message, n: o.commit.committer.name}'
```You can use `$` to avoid using parentheses on the right. That's a
trick from Haskell.Applying functions to nested data structures:
``` haskell
jl '_[0] | \o -> {msg: o.commit.message, n: o.commit.committer.name, ps: map _.html_url o.parents }'
```Notice the `ps` property comes by taking the `html_url` of all the parents.
Filtering is easy, simply write a function that returns true:
``` haskell
jl 'map (\o -> { sha: o.sha, ps: map _.sha o.parents }) | filter (\o -> length o.ps > 1)'
```If you want to make an object with arbitrary keys that come at runtime, use `set`:
``` haskell
$ echo '"hello"' | jl '\x -> set x 123 {}'
{"hello":123}
```This sets the key `x` in the empty object `{}` to `"hello"` with the value `123`.
You can use `set` repeatedly to construct more keys.If you want to construct an object from a list of key/values, you can use `fold`:
```haskell
$ echo '[{"k":"foo","v":123},{"k":"bar","v":456}]' | jl 'fold (\acc o -> set o.k o.v acc) {}'
{"foo":123,"bar":456}
```# Available functions
## Record access
```haskell
get :: JSON → JSON → JSON
```Get the value at k from the object
```haskell
set :: JSON → JSON → JSON → JSON
```Set the value k to v in object
```haskell
modify :: JSON → (JSON → JSON) → JSON → JSON
```Modify the object at k with function f
```haskell
keys :: JSON → JSON
```Get all keys of the object
```haskell
elems :: JSON → JSON
```Get all elements of the object
## Sequences
```haskell
map :: (JSON → JSON) → JSON → JSON
```Apply a function to every element in the sequence
```haskell
filter :: (JSON → JSON) → JSON → JSON
```Keep only items from the sequence for which p returns true
```haskell
takeWhile :: (JSON → JSON) → JSON → JSON
```Take elements from a sequence while given predicate is true
```haskell
empty :: JSON → JSON
```Is a sequence empty?
```haskell
length :: JSON → JSON
```Get the length of a sequence
```haskell
reverse :: JSON → JSON
```Reverse a sequence
```haskell
drop :: JSON → JSON → JSON
```Drop n items from the sequence
```haskell
elem :: JSON → JSON → JSON
```Is x an element of y?
```haskell
concat :: JSON → JSON
```Concatenate a list of sequences into one sequence
```haskell
zipWith :: (JSON → JSON → JSON) → JSON → JSON → JSON
```Zip two lists calling with each element to f x y
```haskell
take :: JSON → JSON → JSON
```Take n items from sequence
```haskell
fold :: (JSON → JSON → JSON) → JSON → JSON → JSON
```Fold over a structure with a state.
```haskell
dropWhile :: (JSON → JSON) → JSON → JSON
```Drop elements from a sequence while a predicate is true
```haskell
any :: (JSON → JSON) → JSON → JSON
```Does p return true for any of the elements?
```haskell
all :: (JSON → JSON) → JSON → JSON
```Does p return true for all of the elements?
```haskell
nub :: JSON → JSON
```Return the sequence with no duplicates; the nub of it
```haskell
sort :: JSON → JSON
```Return the sequence sorted
```haskell
append :: JSON → JSON → JSON
```Append the members of the second sequence to the first sequence
```haskell
sum :: JSON → JSON
```Get the sum of a sequence
```haskell
product :: JSON → JSON
```Get the product of a sequence
```haskell
minimum :: JSON → JSON
```Get the minimum of a sequence
```haskell
maximum :: JSON → JSON
```Get the maximum of a sequence
## Strings
```haskell
words :: JSON → JSON
```Split the string into a list of words
```haskell
unwords :: JSON → JSON
```Join the list of strings into a string separated by spaces
```haskell
lines :: JSON → JSON
```Split the string into a list of lines
```haskell
unlines :: JSON → JSON
```Join the list of strings into a string separated by lines and terminated by a new line
## Predicate operators
```haskell
/= :: JSON → JSON → JSON
```a /= b
```haskell
= :: JSON → JSON → JSON
```a = b
## Boolean operators
```haskell
&& :: JSON → JSON → JSON
```a && b
```haskell
|| :: JSON → JSON → JSON
```a || b
```haskell
not :: JSON → JSON
```not b
## Numeric operators
```haskell
> :: JSON → JSON → JSON
```a > b
```haskell
< :: JSON → JSON → JSON
```a < b
```haskell
>= :: JSON → JSON → JSON
```a >= b
```haskell
<= :: JSON → JSON → JSON
```a <= b
```haskell
* :: JSON → JSON → JSON
```a * b
```haskell
+ :: JSON → JSON → JSON
```a + b
```haskell
- :: JSON → JSON → JSON
```a - b
```haskell
/ :: JSON → JSON → JSON
```a / b
```haskell
min :: JSON → JSON → JSON
```a min b
```haskell
max :: JSON → JSON → JSON
```a max b
```haskell
abs :: JSON → JSON
```abs b
## Function combinators
```haskell
id :: JSON → JSON
```Identity function, returns its input unchanged
```haskell
compose :: (JSON → JSON) → (JSON → JSON) → JSON → JSON
```Compose two functions
```haskell
flip :: (JSON → JSON → JSON) → JSON → JSON → JSON
```Flips the argument order of a function of two or more arguments