fx 20.0.2 → 25.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 +46 -76
- package/index.js +94 -155
- package/package.json +8 -43
- package/LICENSE +0 -21
- package/bang.js +0 -79
- package/config.js +0 -26
- package/find.js +0 -35
- package/fx.js +0 -717
- package/print.js +0 -117
- package/reduce.js +0 -51
- package/std.js +0 -33
- package/stream.js +0 -84
- package/test.js +0 -85
package/README.md
CHANGED
|
@@ -1,108 +1,78 @@
|
|
|
1
|
-
|
|
2
|
-
<p align="center"><img src="https://medv.io/assets/fx.gif" width="562" alt="fx example"></p>
|
|
1
|
+
# fx
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
The JavaScript version of the **fx**. Short for _Function eXecution_ or _f(x)_.
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
Command-line JSON processing tool
|
|
5
|
+
```sh
|
|
6
|
+
npm i -g fx
|
|
7
|
+
```
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
Or use **npx**:
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* Streaming support 🌊
|
|
11
|
+
```sh
|
|
12
|
+
cat file.json | npx fx .param
|
|
13
|
+
```
|
|
18
14
|
|
|
19
|
-
|
|
15
|
+
Or use **node**:
|
|
20
16
|
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
Or via Homebrew
|
|
25
|
-
```bash
|
|
26
|
-
brew install fx
|
|
17
|
+
```sh
|
|
18
|
+
cat file.json | node <(curl -s https://fx.wtf) .param
|
|
27
19
|
```
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
|
|
21
|
+
Or use **deno**:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
cat file.json | deno run https://fx.wtf .param
|
|
31
25
|
```
|
|
32
26
|
|
|
33
27
|
## Usage
|
|
34
28
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
```
|
|
29
|
+
Fx treats arguments as JavaScript functions. Fx passes the input data to the first
|
|
30
|
+
function and then passes the result of the first function to the second function
|
|
31
|
+
and so on.
|
|
39
32
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
$ fx data.json
|
|
33
|
+
```sh
|
|
34
|
+
echo '{"name": "world"}' | fx 'x => x.name' 'x => `Hello, ${x}!`'
|
|
43
35
|
```
|
|
44
36
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
cat foo.json bar.json baz.json | fx .message
|
|
48
|
-
```
|
|
37
|
+
Use `this` to access the input data. Use `.` at the start of the expression to
|
|
38
|
+
access the input data without a `x => x` part.
|
|
49
39
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
$ curl ... | fx '.filter(x => x.startsWith("a"))'
|
|
40
|
+
```sh
|
|
41
|
+
echo '{"name": "world"}' | fx '.name' '`Hello, ${this}!`'
|
|
53
42
|
```
|
|
54
43
|
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
$ curl ... | fx '_.groupBy("commit.committer.name")' '_.mapValues(_.size)'
|
|
58
|
-
```
|
|
44
|
+
Use other JS functions to process the data.
|
|
59
45
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
$ echo '{"count": 0}' | fx '{...this, count: 1}'
|
|
63
|
-
{
|
|
64
|
-
"count": 1
|
|
65
|
-
}
|
|
46
|
+
```sh
|
|
47
|
+
echo `{"name": "world"}` | fx 'Object.keys'
|
|
66
48
|
```
|
|
67
49
|
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
$ fx commits.json | fx .[].author.name
|
|
71
|
-
```
|
|
50
|
+
## Advanced Usage
|
|
72
51
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
$ curl ... | fx .
|
|
76
|
-
```
|
|
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.
|
|
77
54
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
$ kubectl logs ... -f | fx .message
|
|
55
|
+
```sh
|
|
56
|
+
curl https://api.github.com/repos/antonmedv/fx/commits | fx 'map(.commit.message)'
|
|
81
57
|
```
|
|
82
58
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
$ fx --life
|
|
59
|
+
```sh
|
|
60
|
+
echo '[{"name": "world"}]' | fx 'map(`Hello, ${x.name}!`)'
|
|
86
61
|
```
|
|
87
62
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
See full [documentation](https://github.com/antonmedv/fx/blob/master/DOCS.md).
|
|
63
|
+
Fx has a special syntax for the flatMap function. Fox example,
|
|
64
|
+
`.flatMap(x => x.labels.flatMap(x => x.name))` can be rewritten in the next way.
|
|
91
65
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
## Related
|
|
66
|
+
```sh
|
|
67
|
+
curl https://api.github.com/repos/kubernetes/kubernetes/issues | fx '.[].labels[].name'
|
|
68
|
+
```
|
|
97
69
|
|
|
98
|
-
|
|
99
|
-
* [eat](https://github.com/antonmedv/eat) – converts anything into JSON
|
|
100
|
-
* [ymlx](https://github.com/matthewadams/ymlx) – fx-like YAML cli processor
|
|
101
|
-
* [fx-completion](https://github.com/antonmedv/fx-completion) – bash completion for fx
|
|
102
|
-
* [fx-theme-monokai](https://github.com/antonmedv/fx-theme-monokai) – monokai theme
|
|
103
|
-
* [fx-theme-night](https://github.com/antonmedv/fx-theme-night) – night theme
|
|
70
|
+
Fx works with promises.
|
|
104
71
|
|
|
72
|
+
```sh
|
|
73
|
+
echo '"https://medv.io/*"' | fx 'fetch' '.text()'
|
|
74
|
+
```
|
|
105
75
|
|
|
106
76
|
## License
|
|
107
77
|
|
|
108
|
-
[MIT](
|
|
78
|
+
[MIT](../LICENSE)
|
package/index.js
CHANGED
|
@@ -1,177 +1,116 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
JSON.config({circularRefs: false})
|
|
9
|
-
|
|
10
|
-
const std = require('./std')
|
|
11
|
-
|
|
12
|
-
try {
|
|
13
|
-
require(path.join(os.homedir(), '.fxrc')) // Should be required before config.js usage.
|
|
14
|
-
} catch (err) {
|
|
15
|
-
if (err.code !== 'MODULE_NOT_FOUND') {
|
|
16
|
-
throw err
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const print = require('./print')
|
|
21
|
-
const reduce = require('./reduce')
|
|
22
|
-
const stream = require('./stream')
|
|
23
|
-
|
|
24
|
-
const usage = `
|
|
25
|
-
Usage
|
|
26
|
-
$ fx [code ...]
|
|
27
|
-
|
|
28
|
-
Examples
|
|
29
|
-
$ echo '{"key": "value"}' | fx 'x => x.key'
|
|
30
|
-
value
|
|
31
|
-
|
|
32
|
-
$ echo '{"key": "value"}' | fx .key
|
|
33
|
-
value
|
|
34
|
-
|
|
35
|
-
$ echo '[1,2,3]' | fx 'this.map(x => x * 2)'
|
|
36
|
-
[2, 4, 6]
|
|
37
|
-
|
|
38
|
-
$ echo '{"items": ["one", "two"]}' | fx 'this.items' 'this[1]'
|
|
39
|
-
two
|
|
40
|
-
|
|
41
|
-
$ echo '{"count": 0}' | fx '{...this, count: 1}'
|
|
42
|
-
{"count": 1}
|
|
43
|
-
|
|
44
|
-
$ echo '{"foo": 1, "bar": 2}' | fx ?
|
|
45
|
-
["foo", "bar"]
|
|
46
|
-
|
|
47
|
-
`
|
|
48
|
-
|
|
49
|
-
const {stdin, stdout, stderr} = process
|
|
50
|
-
const args = process.argv.slice(2)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
void function main() {
|
|
54
|
-
stdin.setEncoding('utf8')
|
|
55
|
-
|
|
56
|
-
if (stdin.isTTY) {
|
|
57
|
-
handle('')
|
|
58
|
-
return
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const reader = stream(stdin, apply)
|
|
62
|
-
|
|
63
|
-
stdin.on('readable', reader.read)
|
|
64
|
-
stdin.on('end', () => {
|
|
65
|
-
if (!reader.isStream()) {
|
|
66
|
-
handle(reader.value())
|
|
67
|
-
}
|
|
68
|
-
})
|
|
69
|
-
}()
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
function handle(input) {
|
|
73
|
-
let filename = 'fx'
|
|
74
|
-
|
|
75
|
-
if (input === '') {
|
|
76
|
-
if (args.length === 0 || (args.length === 1 && (args[0] === '-h' || args[0] === '--help'))) {
|
|
77
|
-
stderr.write(usage)
|
|
78
|
-
process.exit(2)
|
|
79
|
-
}
|
|
80
|
-
if (args.length === 1 && (args[0] === '-v' || args[0] === '--version')) {
|
|
81
|
-
stderr.write(require('./package.json').version + '\n')
|
|
82
|
-
process.exit(2)
|
|
83
|
-
}
|
|
84
|
-
if (args.length === 1 && args[0] === '--life') {
|
|
85
|
-
require('./bang')
|
|
86
|
-
return
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
input = fs.readFileSync(args[0]).toString('utf8')
|
|
90
|
-
filename = path.basename(args[0])
|
|
91
|
-
global.FX_FILENAME = filename
|
|
92
|
-
args.shift()
|
|
93
|
-
}
|
|
1
|
+
void async function main() {
|
|
2
|
+
const process = await import('node:process')
|
|
3
|
+
const args = process.argv.slice(2)
|
|
4
|
+
let input = ''
|
|
5
|
+
process.stdin.setEncoding('utf8')
|
|
6
|
+
for await (const chunk of process.stdin)
|
|
7
|
+
input += chunk
|
|
94
8
|
|
|
95
9
|
let json
|
|
96
10
|
try {
|
|
97
11
|
json = JSON.parse(input)
|
|
98
|
-
} catch (
|
|
99
|
-
|
|
12
|
+
} catch (err) {
|
|
13
|
+
process.stderr.write(`Invalid JSON: ${err.message}\n`)
|
|
100
14
|
process.exit(1)
|
|
101
15
|
}
|
|
102
16
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function apply(json) {
|
|
112
|
-
let output = json
|
|
113
|
-
|
|
114
|
-
for (let [i, code] of args.entries()) {
|
|
115
|
-
try {
|
|
116
|
-
output = reduce(output, code)
|
|
117
|
-
} catch (e) {
|
|
118
|
-
if (e === std.skip) {
|
|
119
|
-
return
|
|
120
|
-
}
|
|
121
|
-
stderr.write(`${snippet(i, code)}\n${e.stack || e}\n`)
|
|
122
|
-
process.exit(1)
|
|
123
|
-
}
|
|
17
|
+
let i, code, output = json
|
|
18
|
+
for ([i, code] of args.entries()) try {
|
|
19
|
+
output = await transform(output, code)
|
|
20
|
+
} catch (err) {
|
|
21
|
+
printErr(err)
|
|
22
|
+
process.exit(1)
|
|
124
23
|
}
|
|
125
24
|
|
|
126
|
-
if (typeof output === 'undefined')
|
|
127
|
-
stderr.write('undefined\n')
|
|
128
|
-
|
|
25
|
+
if (typeof output === 'undefined')
|
|
26
|
+
process.stderr.write('undefined\n')
|
|
27
|
+
else if (typeof output === 'string')
|
|
129
28
|
console.log(output)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
29
|
+
else
|
|
30
|
+
console.log(JSON.stringify(output, null, 2))
|
|
31
|
+
|
|
32
|
+
function printErr(err) {
|
|
33
|
+
let pre = args.slice(0, i).join(' ')
|
|
34
|
+
let post = args.slice(i + 1).join(' ')
|
|
35
|
+
if (pre.length > 20) pre = '...' + pre.substring(pre.length - 20)
|
|
36
|
+
if (post.length > 20) post = post.substring(0, 20) + '...'
|
|
37
|
+
process.stderr.write(
|
|
38
|
+
`\n ${pre} ${code} ${post}\n` +
|
|
39
|
+
` ${' '.repeat(pre.length + 1)}${'^'.repeat(code.length)}\n` +
|
|
40
|
+
`\n${err.stack || err}\n`
|
|
41
|
+
)
|
|
133
42
|
}
|
|
134
|
-
}
|
|
43
|
+
}()
|
|
135
44
|
|
|
136
|
-
function
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
45
|
+
async function transform(json, code) {
|
|
46
|
+
if ('.' === code)
|
|
47
|
+
return json
|
|
48
|
+
|
|
49
|
+
if ('?' === code)
|
|
50
|
+
return Object.keys(json)
|
|
51
|
+
|
|
52
|
+
if (/^(\.\w*)+\[]/.test(code))
|
|
53
|
+
return eval(`(function () {
|
|
54
|
+
return (${fold(code.split('[]'))})(this)
|
|
55
|
+
})`).call(json)
|
|
56
|
+
|
|
57
|
+
if (/^\.\[/.test(code))
|
|
58
|
+
return eval(`(function () {
|
|
59
|
+
return this${code.substring(1)}
|
|
60
|
+
})`).call(json)
|
|
61
|
+
|
|
62
|
+
if (/^\./.test(code))
|
|
63
|
+
return eval(`(function () {
|
|
64
|
+
return this${code}
|
|
65
|
+
})`).call(json)
|
|
66
|
+
|
|
67
|
+
if (/^map\(.+?\)$/.test(code)) {
|
|
68
|
+
let s = code.substring(4, code.length - 1)
|
|
69
|
+
if (s[0] === '.') s = 'x' + s
|
|
70
|
+
return eval(`(function () {
|
|
71
|
+
return this.map((x, i) => apply(${s}, x, i))
|
|
72
|
+
})`).call(json)
|
|
144
73
|
}
|
|
145
|
-
|
|
146
|
-
|
|
74
|
+
|
|
75
|
+
const fn = eval(`(function () {
|
|
76
|
+
return ${code}
|
|
77
|
+
})`).call(json)
|
|
78
|
+
|
|
79
|
+
return apply(fn, json)
|
|
147
80
|
}
|
|
148
81
|
|
|
149
|
-
function
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (end > input.length) end = input.length
|
|
82
|
+
function apply(fn, ...args) {
|
|
83
|
+
if (typeof fn === 'function') return fn(...args)
|
|
84
|
+
return fn
|
|
85
|
+
}
|
|
154
86
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
87
|
+
function fold(s) {
|
|
88
|
+
if (s.length === 1)
|
|
89
|
+
return 'x => x' + s[0]
|
|
90
|
+
let obj = s.shift()
|
|
91
|
+
obj = obj === '.' ? 'x' : 'x' + obj
|
|
92
|
+
return `x => Object.values(${obj}).flatMap(${fold(s)})`
|
|
93
|
+
}
|
|
158
94
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
95
|
+
function uniq(array) {
|
|
96
|
+
return [...new Set(array)]
|
|
97
|
+
}
|
|
162
98
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
99
|
+
function sort(array) {
|
|
100
|
+
return array.sort()
|
|
101
|
+
}
|
|
167
102
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
103
|
+
function groupBy(keyOrFunction) {
|
|
104
|
+
return array => {
|
|
105
|
+
const grouped = {}
|
|
106
|
+
for (const item of array) {
|
|
107
|
+
const key = typeof keyOrFunction === 'function'
|
|
108
|
+
? keyOrFunction(item)
|
|
109
|
+
: item[keyOrFunction]
|
|
110
|
+
if (!grouped.hasOwnProperty(key))
|
|
111
|
+
grouped[key] = []
|
|
112
|
+
grouped[key].push(item)
|
|
173
113
|
}
|
|
174
|
-
|
|
114
|
+
return grouped
|
|
175
115
|
}
|
|
176
|
-
process.stderr.write(e.toString() + '\n')
|
|
177
116
|
}
|
package/package.json
CHANGED
|
@@ -1,53 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fx",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Command-line JSON viewer",
|
|
5
|
-
"repository": "antonmedv/fx",
|
|
6
|
-
"homepage": "https://fx.wtf",
|
|
7
|
-
"author": "Anton Medvedev <anton@medv.io>",
|
|
8
|
-
"license": "MIT",
|
|
3
|
+
"version": "25.0.0",
|
|
9
4
|
"bin": {
|
|
10
5
|
"fx": "index.js"
|
|
11
6
|
},
|
|
12
7
|
"files": [
|
|
13
|
-
"
|
|
8
|
+
"index.js"
|
|
14
9
|
],
|
|
15
10
|
"scripts": {
|
|
16
|
-
"test": "
|
|
17
|
-
"build": "pkg . --out-path dist",
|
|
18
|
-
"zip": "cd dist && find . -name 'fx-*' -exec zip '{}.zip' '{}' \\;",
|
|
19
|
-
"release": "release-it --github.release --github.assets=dist/*.zip",
|
|
20
|
-
"brew:release": "brew bump-formula-pr --url=https://registry.npmjs.org/fx/-/fx-`fx package.json .version`.tgz --no-audit fx"
|
|
21
|
-
},
|
|
22
|
-
"release-it": {
|
|
23
|
-
"hooks": {
|
|
24
|
-
"after:bump": "rm -rf ./dist && npm run build && npm run zip"
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
"keywords": [
|
|
28
|
-
"json",
|
|
29
|
-
"viewer",
|
|
30
|
-
"cli",
|
|
31
|
-
"terminal",
|
|
32
|
-
"term",
|
|
33
|
-
"console",
|
|
34
|
-
"ascii",
|
|
35
|
-
"unicode",
|
|
36
|
-
"blessed"
|
|
37
|
-
],
|
|
38
|
-
"engines": {
|
|
39
|
-
"node": ">=8"
|
|
40
|
-
},
|
|
41
|
-
"dependencies": {
|
|
42
|
-
"@medv/blessed": "^2.0.1",
|
|
43
|
-
"chalk": "^4.1.0",
|
|
44
|
-
"indent-string": "^4.0.0",
|
|
45
|
-
"lossless-json": "^1.0.4",
|
|
46
|
-
"string-width": "^4.2.0"
|
|
11
|
+
"test": "node test.js"
|
|
47
12
|
},
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
13
|
+
"repository": "antonmedv/fx",
|
|
14
|
+
"homepage": "https://fx.wtf",
|
|
15
|
+
"description": "Command-line JSON viewer",
|
|
16
|
+
"author": "Anton Medvedev <anton@medv.io>",
|
|
17
|
+
"license": "MIT"
|
|
53
18
|
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2019 Anton Medvedev
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/bang.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
// http://bit.ly/fx--life
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
run = f => setInterval(f, 16),
|
|
6
|
-
p = (s) => process.stdout.write(s),
|
|
7
|
-
esc = (...x) => x.map(i => p('\u001B[' + i)),
|
|
8
|
-
[upper, lower, full] = ['\u2580', '\u2584', '\u2588'],
|
|
9
|
-
{columns, rows} = process.stdout,
|
|
10
|
-
[w, h] = [columns, rows * 2],
|
|
11
|
-
a = Math.floor(w / 2) - 6, b = Math.floor(h / 2) - 7
|
|
12
|
-
|
|
13
|
-
let $ = Array(w * h).fill(false)
|
|
14
|
-
if (Date.now() % 3 === 0) {
|
|
15
|
-
$[1 + 5 * w] = $[1 + 6 * w] = $[2 + 5 * w] = $[2 + 6 * w] = $[12 + 5 * w] = $[12 + 6 * w] = $[12 + 7 * w] = $[13 + 4 * w] = $[13 + 8 * w] = $[14 + 3 * w] = $[14 + 9 * w] = $[15 + 4 * w] = $[15 + 8 * w] = $[16 + 5 * w] = $[16 + 6 * w] = $[16 + 7 * w] = $[17 + 5 * w] = $[17 + 6 * w] = $[17 + 7 * w] = $[22 + 3 * w] = $[22 + 4 * w] = $[22 + 5 * w] = $[23 + 2 * w] = $[23 + 3 * w] = $[23 + 5 * w] = $[23 + 6 * w] = $[24 + 2 * w] = $[24 + 3 * w] = $[24 + 5 * w] = $[24 + 6 * w] = $[25 + 2 * w] = $[25 + 3 * w] = $[25 + 4 * w] = $[25 + 5 * w] = $[25 + 6 * w] = $[26 + 1 * w] = $[26 + 2 * w] = $[26 + 6 * w] = $[26 + 7 * w] = $[35 + 3 * w] = $[35 + 4 * w] = $[36 + 3 * w] = $[36 + 4 * w] = true
|
|
16
|
-
} else if (Date.now() % 3 === 1) {
|
|
17
|
-
for (let i = 0; i < $.length; i-=-1)
|
|
18
|
-
if (Math.random() < 0.16) $[i] = true
|
|
19
|
-
} else {
|
|
20
|
-
$[a + 1 + (2 + b) * w] = $[a + 2 + (1 + b) * w] = $[a + 2 + (3 + b) * w] = $[a + 3 + (2 + b) * w] = $[a + 5 + (15 + b) * w] = $[a + 6 + (13 + b) * w] = $[a + 6 + (15 + b) * w] = $[a + 7 + (12 + b) * w] = $[a + 7 + (13 + b) * w] = $[a + 7 + (15 + b) * w] = $[a + 9 + (11 + b) * w] = $[a + 9 + (12 + b) * w] = $[a + 9 + (13 + b) * w] = true
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function at(i, j) {
|
|
24
|
-
if (i < 0) i = h - 1
|
|
25
|
-
if (i >= h) i = 0
|
|
26
|
-
if (j < 0) j = w - 1
|
|
27
|
-
if (j >= w) j = 0
|
|
28
|
-
return $[i * w + j]
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function neighbors(i, j) {
|
|
32
|
-
let c = 0
|
|
33
|
-
at(i - 1, j - 1) && c++
|
|
34
|
-
at(i - 1, j) && c++
|
|
35
|
-
at(i - 1, j + 1) && c++
|
|
36
|
-
at(i, j - 1) && c++
|
|
37
|
-
at(i, j + 1) && c++
|
|
38
|
-
at(i + 1, j - 1) && c++
|
|
39
|
-
at(i + 1, j) && c++
|
|
40
|
-
at(i + 1, j + 1) && c++
|
|
41
|
-
return c
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
run(() => {
|
|
45
|
-
esc('H')
|
|
46
|
-
|
|
47
|
-
let gen = Array(w * h).fill(false)
|
|
48
|
-
for (let i = 0; i < h; i-=-1) {
|
|
49
|
-
for (let j = 0; j < w; j-=-1) {
|
|
50
|
-
const n = neighbors(i, j)
|
|
51
|
-
const z = i * w + j
|
|
52
|
-
if ($[z]) {
|
|
53
|
-
if (n < 2) gen[z] = false
|
|
54
|
-
if (n === 2 || n === 3) gen[z] = true
|
|
55
|
-
if (n > 3) gen[z] = false
|
|
56
|
-
} else {
|
|
57
|
-
if (n === 3) gen[z] = true
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
$ = gen
|
|
62
|
-
|
|
63
|
-
for (let i = 0; i < rows; i-=-1) {
|
|
64
|
-
for (let j = 0; j < columns; j-=-1) {
|
|
65
|
-
if ($[i * 2 * w + j] && $[(i * 2 + 1) * w + j]) p(full)
|
|
66
|
-
else if ($[i * 2 * w + j] && !$[(i * 2 + 1) * w + j]) p(upper)
|
|
67
|
-
else if (!$[i * 2 * w + j] && $[(i * 2 + 1) * w + j]) p(lower)
|
|
68
|
-
else p(' ')
|
|
69
|
-
}
|
|
70
|
-
if (i !== rows - 1) p('\n')
|
|
71
|
-
}
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
esc('2J', '?25l')
|
|
75
|
-
|
|
76
|
-
process.on('SIGINT', () => {
|
|
77
|
-
esc('?25h')
|
|
78
|
-
process.exit(2)
|
|
79
|
-
})
|
package/config.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
const chalk = require('chalk')
|
|
3
|
-
const noop = x => x
|
|
4
|
-
const list = {
|
|
5
|
-
fg: 'black',
|
|
6
|
-
bg: 'cyan',
|
|
7
|
-
selected: {
|
|
8
|
-
bg: 'magenta'
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
module.exports = {
|
|
13
|
-
space: global.FX_STYLE_SPACE || 2,
|
|
14
|
-
null: global.FX_STYLE_NULL || chalk.grey.bold,
|
|
15
|
-
number: global.FX_STYLE_NUMBER || chalk.cyan.bold,
|
|
16
|
-
boolean: global.FX_STYLE_BOOLEAN || chalk.yellow.bold,
|
|
17
|
-
string: global.FX_STYLE_STRING || chalk.green.bold,
|
|
18
|
-
key: global.FX_STYLE_KEY || chalk.blue.bold,
|
|
19
|
-
bracket: global.FX_STYLE_BRACKET || noop,
|
|
20
|
-
comma: global.FX_STYLE_COMMA || noop,
|
|
21
|
-
colon: global.FX_STYLE_COLON || noop,
|
|
22
|
-
list: global.FX_STYLE_LIST || list,
|
|
23
|
-
highlight: global.FX_STYLE_HIGHLIGHT || chalk.black.bgYellow,
|
|
24
|
-
highlightCurrent: global.FX_STYLE_HIGHLIGHT_CURRENT || chalk.inverse,
|
|
25
|
-
statusBar: global.FX_STYLE_STATUS_BAR || chalk.inverse,
|
|
26
|
-
}
|
package/find.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
function* find(v, regex, path = []) {
|
|
4
|
-
if (typeof v === 'undefined' || v === null) {
|
|
5
|
-
return
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
if (Array.isArray(v)) {
|
|
9
|
-
let i = 0
|
|
10
|
-
for (let value of v) {
|
|
11
|
-
yield* find(value, regex, path.concat(['[' + i++ + ']']))
|
|
12
|
-
}
|
|
13
|
-
return
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (typeof v === 'object' && v.constructor === Object) {
|
|
17
|
-
const entries = Object.entries(v)
|
|
18
|
-
for (let [key, value] of entries) {
|
|
19
|
-
const nextPath = path.concat(['.' + key])
|
|
20
|
-
|
|
21
|
-
if (regex.test(key)) {
|
|
22
|
-
yield nextPath
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
yield* find(value, regex, nextPath)
|
|
26
|
-
}
|
|
27
|
-
return
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (regex.test(v)) {
|
|
31
|
-
yield path
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
module.exports = find
|