fx 34.0.0 → 36.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.
- package/README.md +22 -10
- package/index.js +48 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ cat file.json | npx fx .field
|
|
|
16
16
|
Or use **deno**:
|
|
17
17
|
|
|
18
18
|
```sh
|
|
19
|
-
cat file.json | deno run -A
|
|
19
|
+
cat file.json | deno run -A npm:fx .field
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
## Usage
|
|
@@ -42,7 +42,7 @@ Use other JS functions to process the data.
|
|
|
42
42
|
echo '{"name": "world"}' | fx 'Object.keys'
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
### Stream processing
|
|
46
46
|
|
|
47
47
|
Fx can process a stream of json objects. Fx will apply arguments to each object.
|
|
48
48
|
|
|
@@ -57,6 +57,8 @@ use the **--slurp** or **-s** flag.
|
|
|
57
57
|
echo '{"name": "hello"}\n{"name": "world"}' | fx --slurp '.map(x => x.name)' '.join(", ")'
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
+
### Raw input
|
|
61
|
+
|
|
60
62
|
If you want to process non-JSON data, use the **--raw** or **-r** flag.
|
|
61
63
|
|
|
62
64
|
```sh
|
|
@@ -75,18 +77,24 @@ Fx has a special symbol **skip** for skipping the printing of the result.
|
|
|
75
77
|
ls | fx -r '.includes(".md") ? this : skip'
|
|
76
78
|
```
|
|
77
79
|
|
|
80
|
+
### Built-in functions
|
|
81
|
+
|
|
78
82
|
Fx comes with a set of useful functions: **uniq**, **sort**, **groupBy**, **chunk**, **zip**.
|
|
79
83
|
|
|
80
84
|
```sh
|
|
81
85
|
cat file.json | fx 'uniq' 'sort' 'groupBy(x => x.name)'
|
|
82
86
|
```
|
|
83
87
|
|
|
84
|
-
|
|
88
|
+
### Edit-in-place
|
|
89
|
+
|
|
90
|
+
You can use special function **save** to edit-in-place the input data.
|
|
85
91
|
|
|
86
92
|
```sh
|
|
87
|
-
|
|
93
|
+
fx file.json 'x.name = x.name.toUpperCase(), x' 'save'
|
|
88
94
|
```
|
|
89
95
|
|
|
96
|
+
The edited data will be saved to the same `file.json` file.
|
|
97
|
+
|
|
90
98
|
### Syntactic Sugar
|
|
91
99
|
|
|
92
100
|
Fx has a shortcut for the map function. Fox example, `this.map(x => x.commit.message)`
|
|
@@ -101,28 +109,32 @@ echo '[{"name": "world"}]' | fx 'map(`Hello, ${x.name}!`)'
|
|
|
101
109
|
```
|
|
102
110
|
|
|
103
111
|
Fx has a special syntax for the flatMap function. Fox example,
|
|
104
|
-
`.flatMap(x => x.labels.flatMap(x => x
|
|
112
|
+
`.issues.flatMap(x => x.labels.flatMap(x => x))` can be rewritten in the next way.
|
|
105
113
|
|
|
106
114
|
```sh
|
|
107
|
-
curl https://
|
|
115
|
+
curl https://fx.wtf/example.json | fx '.issues[].labels[]'
|
|
108
116
|
```
|
|
109
117
|
|
|
110
118
|
### .fxrc.js
|
|
111
119
|
|
|
112
|
-
Fx supports `.fxrc.js` file in the current directory or in the home directory.
|
|
120
|
+
Fx supports `.fxrc.js` file in the current directory, or in the home directory, or in XDG config directory.
|
|
113
121
|
|
|
114
122
|
Put the next code in the `.fxrc.js` file to make `myFunction` available in the fx.
|
|
115
123
|
|
|
116
124
|
```js
|
|
117
|
-
|
|
125
|
+
function addOne(x) {
|
|
126
|
+
return x + 1
|
|
127
|
+
}
|
|
118
128
|
```
|
|
119
129
|
|
|
120
|
-
Now you can use `
|
|
130
|
+
Now you can use `addOne` in the fx.
|
|
121
131
|
|
|
122
132
|
```sh
|
|
123
|
-
echo '1' | fx
|
|
133
|
+
echo '1' | fx addOne
|
|
124
134
|
```
|
|
125
135
|
|
|
136
|
+
If you would like to create global variables use `var` instead of `let` or `const`.
|
|
137
|
+
|
|
126
138
|
## License
|
|
127
139
|
|
|
128
140
|
[MIT](../LICENSE)
|
package/index.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
void async function main() {
|
|
5
5
|
const os = await import('node:os')
|
|
6
6
|
const fs = await import('node:fs')
|
|
7
|
+
const path = await import('node:path')
|
|
7
8
|
const process = await import('node:process')
|
|
8
9
|
|
|
9
10
|
let flagHelp = false
|
|
@@ -26,8 +27,7 @@ void async function main() {
|
|
|
26
27
|
|
|
27
28
|
const theme = themes(process.stdout.isTTY ? (process.env.FX_THEME || '1') : '0')
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
await importFxrc(os.homedir())
|
|
30
|
+
loadFxrc(os, fs, path, process)
|
|
31
31
|
|
|
32
32
|
let fd = 0 // stdin
|
|
33
33
|
if (args.length > 0) {
|
|
@@ -35,6 +35,7 @@ void async function main() {
|
|
|
35
35
|
isFile(fs, args[0]) ? args.shift() :
|
|
36
36
|
isFile(fs, args.at(-1)) ? args.pop() : false
|
|
37
37
|
if (filename) {
|
|
38
|
+
globalThis.__file__ = filename
|
|
38
39
|
fd = fs.openSync(filename, 'r')
|
|
39
40
|
if (!flagYaml) flagYaml = /\.ya?ml$/i.test(filename)
|
|
40
41
|
}
|
|
@@ -138,6 +139,7 @@ function transpile(code) {
|
|
|
138
139
|
}
|
|
139
140
|
|
|
140
141
|
async function run(json, code) {
|
|
142
|
+
const fs = await import('node:fs')
|
|
141
143
|
const fn = eval(code).call(json)
|
|
142
144
|
|
|
143
145
|
return apply(fn, json)
|
|
@@ -241,6 +243,12 @@ async function run(json, code) {
|
|
|
241
243
|
}
|
|
242
244
|
throw new Error(`Cannot list ${typeof x}`)
|
|
243
245
|
}
|
|
246
|
+
|
|
247
|
+
function save(x) {
|
|
248
|
+
if (!globalThis.__file__) throw new Error('Specify a file as the first argument to be able to save: fx file.json ...')
|
|
249
|
+
fs.writeFileSync(globalThis.__file__, JSON.stringify(x, null, 2))
|
|
250
|
+
return x
|
|
251
|
+
}
|
|
244
252
|
}
|
|
245
253
|
|
|
246
254
|
async function read(fd = 0) {
|
|
@@ -272,8 +280,12 @@ async function read(fd = 0) {
|
|
|
272
280
|
}
|
|
273
281
|
|
|
274
282
|
function isFile(fs, path) {
|
|
275
|
-
|
|
276
|
-
|
|
283
|
+
try {
|
|
284
|
+
const stat = fs.statSync(path, {throwIfNoEntry: false})
|
|
285
|
+
return stat !== undefined && stat.isFile()
|
|
286
|
+
} catch (err) {
|
|
287
|
+
return false
|
|
288
|
+
}
|
|
277
289
|
}
|
|
278
290
|
|
|
279
291
|
function sleepSync(ms) {
|
|
@@ -290,6 +302,7 @@ function* readLine(stdin) {
|
|
|
290
302
|
buffer += ch
|
|
291
303
|
}
|
|
292
304
|
}
|
|
305
|
+
if (buffer.length > 0) yield buffer
|
|
293
306
|
return buffer
|
|
294
307
|
}
|
|
295
308
|
|
|
@@ -678,6 +691,37 @@ async function importFxrc(path) {
|
|
|
678
691
|
}
|
|
679
692
|
}
|
|
680
693
|
|
|
694
|
+
function loadFxrc(os, fs, path, process) {
|
|
695
|
+
let script = ''
|
|
696
|
+
|
|
697
|
+
const cwd = process.cwd()
|
|
698
|
+
const home = os.homedir()
|
|
699
|
+
const xdgHome = process.env.XDG_CONFIG_HOME || path.join(home, '.config')
|
|
700
|
+
const xdgDirsEnv = process.env.XDG_CONFIG_DIRS || '/etc/xdg'
|
|
701
|
+
|
|
702
|
+
const paths = [path.join(cwd, '.fxrc.js')]
|
|
703
|
+
paths.push(path.join(home, '.fxrc.js'))
|
|
704
|
+
paths.push(path.join(xdgHome, 'fx', '.fxrc.js'))
|
|
705
|
+
for (const dir of xdgDirsEnv.split(':')) {
|
|
706
|
+
paths.push(path.join(dir, 'fx', '.fxrc.js'))
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
for (const filePath of paths) {
|
|
710
|
+
try {
|
|
711
|
+
const stat = fs.statSync(filePath)
|
|
712
|
+
if (stat.isDirectory()) continue
|
|
713
|
+
|
|
714
|
+
const data = fs.readFileSync(filePath, 'utf8')
|
|
715
|
+
script += data + '\n'
|
|
716
|
+
} catch (err) {
|
|
717
|
+
if (err.code === 'ENOENT') continue
|
|
718
|
+
throw new Error(`read ${filePath}: ${err.message}`)
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
eval?.(script)
|
|
723
|
+
}
|
|
724
|
+
|
|
681
725
|
function printUsage() {
|
|
682
726
|
const usage = `Usage
|
|
683
727
|
fx [flags] [code...]
|