fx/DOCS.md

331 lines
8.8 KiB
Markdown
Raw Normal View History

2018-12-02 15:13:31 +00:00
# Documentation
2019-03-07 16:38:40 +00:00
* [Getting started](#getting-started)
2019-03-07 16:45:37 +00:00
* [Usage](#usage)
+ [Anonymous function](#anonymous-function)
+ [Binding](#binding)
+ [Dot](#dot)
2020-01-09 09:49:19 +00:00
+ [Map](#map)
2019-03-07 16:45:37 +00:00
+ [Chaining](#chaining)
+ [Updating](#updating)
2019-12-09 06:24:33 +00:00
+ [Edit-in-place](#edit-in-place)
2019-03-07 16:45:37 +00:00
+ [Using packages](#using-packages)
2019-03-07 16:38:40 +00:00
* [Using .fxrc](#using-fxrc)
2019-12-25 13:29:43 +00:00
+ [Query language](#query-language)
2019-03-07 16:38:40 +00:00
* [Formatting](#formatting)
* [Other examples](#other-examples)
* [Streaming mode](#streaming-mode)
2019-12-09 06:24:33 +00:00
+ [Filtering](#filtering)
2019-03-07 16:38:40 +00:00
* [Interactive mode](#interactive-mode)
2019-03-07 16:45:37 +00:00
+ [Searching](#searching)
2019-03-07 16:38:40 +00:00
+ [Selecting text](#selecting-text)
2019-04-03 17:14:19 +00:00
* [Memory Usage](#memory-usage)
2019-03-07 16:38:40 +00:00
## Getting started
`fx` can work in two modes: cli and interactive. To start interactive mode pipe any JSON into `fx`:
2018-12-02 15:13:31 +00:00
2018-12-13 05:43:12 +00:00
```bash
2018-12-02 15:13:31 +00:00
$ curl ... | fx
```
Or you can pass a filename as the first parameter:
2018-12-02 15:13:31 +00:00
2018-12-13 05:43:12 +00:00
```bash
2018-12-02 15:13:31 +00:00
$ fx my.json
```
If any argument was passed, `fx` will apply it and prints to stdout.
2019-03-07 16:45:37 +00:00
## Usage
### Anonymous function
2018-12-02 15:13:31 +00:00
Use an anonymous function as reducer which gets JSON and processes it:
2018-12-13 05:43:12 +00:00
```bash
2018-12-02 15:13:31 +00:00
$ echo '{"foo": [{"bar": "value"}]}' | fx 'x => x.foo[0].bar'
value
```
2019-03-07 16:45:37 +00:00
### Binding
2018-12-02 15:13:31 +00:00
If you don't pass anonymous function `param => ...`, code will be automatically transformed into anonymous function.
And you can get access to JSON by `this` keyword:
2018-12-13 05:43:12 +00:00
```bash
2018-12-02 15:13:31 +00:00
$ echo '{"foo": [{"bar": "value"}]}' | fx 'this.foo[0].bar'
value
```
2019-03-07 16:45:37 +00:00
### Dot
2018-12-02 15:13:31 +00:00
It is possible to omit `this` keyword:
2018-12-13 05:43:12 +00:00
```bash
2018-12-02 15:13:31 +00:00
$ echo '{"foo": [{"bar": "value"}]}' | fx .foo[0].bar
value
```
If a single dot is passed, the input JSON will be formatted but otherwise unaltered:
2018-12-13 05:43:12 +00:00
```bash
2018-12-02 15:13:31 +00:00
$ echo '{"foo": "bar"}' | fx .
{
"foo": "bar"
}
```
2020-01-09 09:49:19 +00:00
### Map
One of the frequent operations is mapping some function on an array. For example, to extract some values.
```
[
{
"author": {
"name": "antonmedv"
2020-09-03 21:54:32 +00:00
}
2020-01-09 09:49:19 +00:00
},
{...},
...
]
```
2020-09-03 21:54:32 +00:00
And we want to collect names of each object in the array. We can do this by mapping anonymous function:
2020-01-09 09:49:19 +00:00
```bash
$ cat ... | fx '.map(x => x.author.name)'
```
2020-09-03 21:54:32 +00:00
Or we can do the same by using jq-like syntax:
2020-01-09 09:49:19 +00:00
```bash
2020-09-03 21:54:32 +00:00
$ cat ... | fx .[].author.name
2020-01-09 09:49:19 +00:00
[
"antonmedv",
...
]
```
2020-09-03 21:54:32 +00:00
> Note what `[]` can be applied to map object values.
2020-01-09 09:49:19 +00:00
> ```bash
2020-09-03 21:54:32 +00:00
> $ echo '{"foo": 1, "bar": 2}' | fx .[]
> [1, 2]
2020-01-09 09:49:19 +00:00
> ```
2020-09-03 21:54:32 +00:00
2020-01-09 09:49:19 +00:00
2019-03-07 16:45:37 +00:00
### Chaining
2018-12-02 15:13:31 +00:00
You can pass any number of anonymous functions for reducing JSON:
2018-12-13 05:43:12 +00:00
```bash
2018-12-02 15:13:31 +00:00
$ echo '{"foo": [{"bar": "value"}]}' | fx 'x => x.foo' 'this[0]' 'this.bar'
value
```
2019-03-07 16:45:37 +00:00
### Updating
2018-12-02 15:13:31 +00:00
You can update existing JSON using the spread operator:
2018-12-02 15:13:31 +00:00
2018-12-13 05:43:12 +00:00
```bash
2018-12-02 15:13:31 +00:00
$ echo '{"count": 0}' | fx '{...this, count: 1}'
{
"count": 1
}
```
2019-12-09 06:24:33 +00:00
### Edit-in-place
`fx` provides a function `save` which will save everything in place and return saved object.
This function can be only used with filename as first argument to `fx` command.
Usage:
```bash
fx data.json '{...this, count: this.count+1}' save .count
```
2019-03-07 16:45:37 +00:00
### Using packages
2018-12-02 15:13:31 +00:00
Use any npm package by installing it globally:
2018-12-13 05:43:12 +00:00
```bash
2018-12-02 15:13:31 +00:00
$ npm install -g lodash
$ cat package.json | fx 'require("lodash").keys(this.dependencies)'
```
## Using .fxrc
Create _.fxrc_ file in `$HOME` directory, and require any packages or define global functions.
For example, access all lodash methods without `_` prefix. Put in your `.fxrc` file:
```js
2018-12-12 03:40:13 +00:00
Object.assign(global, require('lodash/fp'))
2018-12-02 15:13:31 +00:00
```
And now you will be able to call all lodash methods. For example, see who's been committing to react recently:
2018-12-13 05:43:12 +00:00
```bash
2018-12-02 15:13:31 +00:00
curl 'https://api.github.com/repos/facebook/react/commits?per_page=100' \
2018-12-12 03:40:13 +00:00
| fx 'groupBy("commit.author.name")' 'mapValues(size)' toPairs 'sortBy(1)' reverse 'take(10)' fromPairs
2018-12-02 15:13:31 +00:00
```
> To be able require global modules make sure you have correct `NODE_PATH` env variable.
> ```bash
2019-02-19 13:51:14 +00:00
> export NODE_PATH=`npm root -g`
2018-12-02 15:13:31 +00:00
> ```
2019-12-25 13:29:43 +00:00
### Query language
If you want to use query language, for example [jsonata](http://jsonata.org/) you can use helper function like this:
```js
global.jsonata = expr => require('jsonata')(expr).evaluate
```
And use it like this:
```bash
curl ... | fx 'jsonata("$sum(Order.Product.(Price * Quantity))")'
```
Instead you can create next alias in _.bashrc_ file:
```bash
alias jsonata='FX_APPLY=jsonata fx'
```
And now all code arguments to `jsonata` will be passed through `jsonata` helper. And now you can use it like this:
```bash
curl ... | jsonata '$sum(Order.Product.(Price * Quantity))'
```
2018-12-02 15:13:31 +00:00
## Formatting
If you need output other than JSON (for example arguments for xargs), do not return anything from the reducer.
2018-12-02 15:13:31 +00:00
`undefined` value is printed into stderr by default.
2018-12-13 05:43:12 +00:00
```bash
2018-12-02 15:13:31 +00:00
echo '[]' | fx 'void 0'
undefined
```
2018-12-13 05:43:12 +00:00
```bash
2020-03-20 07:39:04 +00:00
echo '[1,2,3]' | fx 'this.forEach(x => console.log(+x))' 2>/dev/null | xargs echo
2018-12-02 15:13:31 +00:00
1 2 3
```
## Other examples
Convert object to array:
2018-12-13 05:43:12 +00:00
```bash
2018-12-02 15:13:31 +00:00
$ cat package.json | fx 'Object.keys(this.dependencies)'
```
2019-03-07 11:29:05 +00:00
Or by two functions:
```bash
$ cat package.json | fx .dependencies Object.keys
```
By the way, fx has shortcut for `Object.keys`. Previous example can be rewritten as:
2018-12-02 15:13:31 +00:00
2018-12-13 05:43:12 +00:00
```bash
2019-03-07 11:29:05 +00:00
$ cat package.json | fx .dependencies ?
2018-12-02 15:13:31 +00:00
```
2019-02-24 18:57:47 +00:00
## Streaming mode
`fx` supports line-delimited JSON and concatenated JSON streaming.
```bash
$ kubectl logs ... | fx .message
2019-12-09 06:24:33 +00:00
```
> Note what is object lacks `message` field, _undefined_ will be printed to stderr.
> This is useful to see if you are skipping some objects. But if you want to hide them,
> redirect stderr to `/dev/null`.
### Filtering
2019-02-24 18:57:47 +00:00
Sometimes it is necessary to omit some messages in JSON stream, or select only specified log messages.
2019-12-09 06:24:33 +00:00
For this purpose, `fx` has special helpers `select`/`filter`, pass function into it to select/filter JSON messages.
```bash
$ kubectl logs ... | fx 'select(x => x.status == 500)' .message
```
2019-02-24 18:57:47 +00:00
```bash
2019-12-09 06:24:33 +00:00
$ kubectl logs ... | fx 'filter(x => x.status < 499)' .message
2019-02-24 18:57:47 +00:00
```
2020-09-03 15:46:06 +00:00
> If `filter`/`select` overridden in _.fxrc_ you still able to access them with prefix:
2019-12-09 06:24:33 +00:00
> `std.select(cb)` or `std.filter(cd)`
2019-02-24 18:57:47 +00:00
2018-12-02 15:13:31 +00:00
## Interactive mode
Click on fields to expand or collapse JSON tree, use mouse wheel to scroll view.
Next commands available in interactive mode:
2019-12-09 06:24:33 +00:00
| Key | Command |
|-------------------------------|----------------------------------------------|
| `q` or `Esc` or `Ctrl`+`c` | Exit |
| `up` or `k` | Move cursor up |
| `down` or `j` | Move cursor down |
| `left` or `h` | Collapse |
| `right` or `l` | Expand |
| `Shift`+`right` or `L` | Expand all under cursor |
| `e` | Expand all |
| `E` | Collapse all |
| `g` | Scroll to top |
| `G` | Scroll to bottom |
| `.` | Edit filter |
| `/` | Search |
| `n` | Find next |
| `p` | Exit and print JSON to stdout |
| `P` | Exit and print fully expanded JSON to stdout |
2018-12-03 05:14:41 +00:00
These commands are available when editing the filter:
| Key | Command |
|-------------------------------|-------------------------|
| `Enter` | Apply filter |
| `Ctrl`+`u` | Clear filter |
| `Ctrl`+`w` | Delete last part |
| `up`/`down` | Select autocomplete |
2018-12-02 15:13:31 +00:00
2019-03-07 16:45:37 +00:00
### Searching
2018-12-15 07:14:44 +00:00
Press `/` and type regexp pattern to search in current JSON. Search work with currently applied filter.
Examples of pattern and corresponding regexp:
| Pattern | RegExp |
|------------|-------------|
| `/apple` | `/apple/ig` |
| `/apple/` | `/apple/` |
| `/apple/u` | `/apple/u` |
| `/\w+` | `/\w+/ig` |
2018-12-02 15:13:31 +00:00
### Selecting text
You may found what you can't just select text in fx. This is due the fact that all mouse events redirected to stdin. To be able select again you need instruct your terminal not to do it. This can be done by holding special keys while selecting:
2018-12-03 05:14:41 +00:00
| Key | Terminal |
2018-12-02 15:13:31 +00:00
|------------------|---------------|
| `Option`+`Mouse` | iTerm2, Hyper |
| `Fn`+`Mouse` | Terminal.app |
| `Shift`+`Mouse` | Linux |
2019-04-03 17:14:19 +00:00
2019-12-09 06:24:33 +00:00
> Note what you can press `p`/`P` to print everything to stdout and select if there.
2019-04-03 17:14:19 +00:00
## Memory Usage
You may find that sometimes, on really big JSON files, fx prints an error message like this:
2019-04-03 17:14:19 +00:00
```
FATAL ERROR: JavaScript heap out of memory
```
V8 limits memory usage to around 2 GB by default. You can increase the limit by putting this line in your _.profile_:
2019-04-03 17:14:19 +00:00
```bash
export NODE_OPTIONS='--max-old-space-size=8192'
```