fx 24.1.0 → 26.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +33 -7
  2. package/index.js +49 -15
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -9,19 +9,19 @@ npm i -g fx
9
9
  Or use **npx**:
10
10
 
11
11
  ```sh
12
- cat file.json | npx fx .param
12
+ cat file.json | npx fx .field
13
13
  ```
14
14
 
15
15
  Or use **node**:
16
16
 
17
17
  ```sh
18
- cat file.json | node <(curl -s https://fx.wtf) .param
18
+ cat file.json | node <(curl -s https://fx.wtf) .field
19
19
  ```
20
20
 
21
21
  Or use **deno**:
22
22
 
23
23
  ```sh
24
- cat file.json | deno run https://fx.wtf .param
24
+ cat file.json | deno run https://fx.wtf .field
25
25
  ```
26
26
 
27
27
  ## Usage
@@ -41,20 +41,46 @@ access the input data without a `x => x` part.
41
41
  echo '{"name": "world"}' | fx '.name' '`Hello, ${this}!`'
42
42
  ```
43
43
 
44
- Fx has a shortcut for the map function. Fox example `.map(x => x.commit.message)`
45
- can be written without leading dot and without `x =>` parts.
44
+ Use other JS functions to process the data.
46
45
 
47
46
  ```sh
48
- curl https://api.github.com/repos/antonmedv/fx/commits | fx 'map(x.commit.message)'
47
+ echo `{"name": "world"}` | fx 'Object.keys'
48
+ ```
49
+
50
+ ## Advanced Usage
51
+
52
+ Fx has a shortcut for the map function. Fox example, `this.map(x => x.commit.message)`
53
+ can be rewritten without leading dot and without `x => x` parts.
54
+
55
+ ```sh
56
+ curl https://api.github.com/repos/antonmedv/fx/commits | fx 'map(.commit.message)'
57
+ ```
58
+
59
+ ```sh
60
+ echo '[{"name": "world"}]' | fx 'map(`Hello, ${x.name}!`)'
49
61
  ```
50
62
 
51
63
  Fx has a special syntax for the flatMap function. Fox example,
52
- `.flatMap(x => x.labels.flatMap(x => x.name))` can be written in the next way.
64
+ `.flatMap(x => x.labels.flatMap(x => x.name))` can be rewritten in the next way.
53
65
 
54
66
  ```sh
55
67
  curl https://api.github.com/repos/kubernetes/kubernetes/issues | fx '.[].labels[].name'
56
68
  ```
57
69
 
70
+ Fx works with promises.
71
+
72
+ ```sh
73
+ echo '"https://medv.io/*"' | fx 'fetch' '.text()'
74
+ ```
75
+
76
+ When using the **-r** or **--raw** flag, the input will be treated as a raw string
77
+ instead of JSON. This can be useful when working with non-JSON input data, such as
78
+ plain text or CSV data.
79
+
80
+ ```sh
81
+ ls | fx -r '.trim().split("\n")'
82
+ ```
83
+
58
84
  ## License
59
85
 
60
86
  [MIT](../LICENSE)
package/index.js CHANGED
@@ -1,26 +1,32 @@
1
+ #!/usr/bin/env node
1
2
  void async function main() {
2
3
  const process = await import('node:process')
4
+ const args = process.argv.slice(2)
5
+ if ((args.length === 0 && process.stdin.isTTY)
6
+ || (args.length === 1 && ['-h', '--help'].includes(args[0]))) {
7
+ printUsage()
8
+ return
9
+ }
10
+
3
11
  let input = ''
4
12
  process.stdin.setEncoding('utf8')
5
13
  for await (const chunk of process.stdin)
6
14
  input += chunk
7
- const args = process.argv.slice(2)
8
15
 
9
16
  let json
10
- try {
17
+ if (['-r', '--raw'].includes(args[0])) {
18
+ args.shift()
19
+ json = input
20
+ } else try {
11
21
  json = JSON.parse(input)
12
22
  } catch (err) {
13
- try {
14
- json = eval(`(${input})`)
15
- } catch (_) {
16
- process.stderr.write(`Invalid JSON: ${err.message}\n`)
17
- process.exit(1)
18
- }
23
+ process.stderr.write(`Invalid JSON: ${err.message}\n`)
24
+ process.exit(1)
19
25
  }
20
26
 
21
27
  let i, code, output = json
22
28
  for ([i, code] of args.entries()) try {
23
- output = transform(output, code)
29
+ output = await transform(output, code)
24
30
  } catch (err) {
25
31
  printErr(err)
26
32
  process.exit(1)
@@ -46,7 +52,7 @@ void async function main() {
46
52
  }
47
53
  }()
48
54
 
49
- function transform(json, code) {
55
+ async function transform(json, code) {
50
56
  if ('.' === code)
51
57
  return json
52
58
 
@@ -68,20 +74,23 @@ function transform(json, code) {
68
74
  return this${code}
69
75
  })`).call(json)
70
76
 
71
- if (/^map\(.+?\)$/.test(code))
77
+ if (/^map\(.+?\)$/.test(code)) {
78
+ let s = code.substring(4, code.length - 1)
79
+ if (s[0] === '.') s = 'x' + s
72
80
  return eval(`(function () {
73
- return this.map(x => apply(x, ${code.substring(4, code.length - 1)}))
81
+ return this.map((x, i) => apply(${s}, x, i))
74
82
  })`).call(json)
83
+ }
75
84
 
76
85
  const fn = eval(`(function () {
77
86
  return ${code}
78
87
  })`).call(json)
79
88
 
80
- return apply(json, fn)
89
+ return apply(fn, json)
81
90
  }
82
91
 
83
- function apply(json, fn) {
84
- if (typeof fn === 'function') return fn(json)
92
+ function apply(fn, ...args) {
93
+ if (typeof fn === 'function') return fn(...args)
85
94
  return fn
86
95
  }
87
96
 
@@ -100,3 +109,28 @@ function uniq(array) {
100
109
  function sort(array) {
101
110
  return array.sort()
102
111
  }
112
+
113
+ function groupBy(keyOrFunction) {
114
+ return array => {
115
+ const grouped = {}
116
+ for (const item of array) {
117
+ const key = typeof keyOrFunction === 'function'
118
+ ? keyOrFunction(item)
119
+ : item[keyOrFunction]
120
+ if (!grouped.hasOwnProperty(key))
121
+ grouped[key] = []
122
+ grouped[key].push(item)
123
+ }
124
+ return grouped
125
+ }
126
+ }
127
+
128
+ function printUsage() {
129
+ const usage = `Usage
130
+ fx [flags] [code...]
131
+
132
+ Flags
133
+ -h, --help Display this help message
134
+ -r, --raw Treat input as raw string`
135
+ console.log(usage)
136
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fx",
3
- "version": "24.1.0",
3
+ "version": "26.0.0",
4
4
  "bin": {
5
5
  "fx": "index.js"
6
6
  },