fx 20.0.1 → 24.1.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 +34 -82
- package/index.js +82 -154
- 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/json.js +0 -5
- package/print.js +0 -117
- package/reduce.js +0 -50
- package/std.js +0 -33
- package/stream.js +0 -84
- package/test.js +0 -85
package/README.md
CHANGED
|
@@ -1,108 +1,60 @@
|
|
|
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
|
-
[](https://formulae.brew.sh/formula/fx)
|
|
9
|
-
|
|
10
|
-
Command-line JSON processing tool
|
|
11
|
-
|
|
12
|
-
## Features
|
|
13
|
-
|
|
14
|
-
* Easy to use
|
|
15
|
-
* Standalone binary
|
|
16
|
-
* Interactive mode 🎉
|
|
17
|
-
* Streaming support 🌊
|
|
18
|
-
|
|
19
|
-
## Install
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npm install -g fx
|
|
23
|
-
```
|
|
24
|
-
Or via Homebrew
|
|
25
|
-
```bash
|
|
26
|
-
brew install fx
|
|
27
|
-
```
|
|
28
|
-
Or download standalone binary from [releases](https://github.com/antonmedv/fx/releases)
|
|
29
|
-
```bash
|
|
30
|
-
bash <( curl https://fx.wtf )
|
|
5
|
+
```sh
|
|
6
|
+
npm i -g fx
|
|
31
7
|
```
|
|
32
8
|
|
|
33
|
-
|
|
9
|
+
Or use **npx**:
|
|
34
10
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
$ curl ... | fx
|
|
11
|
+
```sh
|
|
12
|
+
cat file.json | npx fx .param
|
|
38
13
|
```
|
|
39
14
|
|
|
40
|
-
Or
|
|
41
|
-
```bash
|
|
42
|
-
$ fx data.json
|
|
43
|
-
```
|
|
15
|
+
Or use **node**:
|
|
44
16
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
cat foo.json bar.json baz.json | fx .message
|
|
17
|
+
```sh
|
|
18
|
+
cat file.json | node <(curl -s https://fx.wtf) .param
|
|
48
19
|
```
|
|
49
20
|
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
$ curl ... | fx '.filter(x => x.startsWith("a"))'
|
|
53
|
-
```
|
|
21
|
+
Or use **deno**:
|
|
54
22
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
$ curl ... | fx '_.groupBy("commit.committer.name")' '_.mapValues(_.size)'
|
|
23
|
+
```sh
|
|
24
|
+
cat file.json | deno run https://fx.wtf .param
|
|
58
25
|
```
|
|
59
26
|
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
$ echo '{"count": 0}' | fx '{...this, count: 1}'
|
|
63
|
-
{
|
|
64
|
-
"count": 1
|
|
65
|
-
}
|
|
66
|
-
```
|
|
27
|
+
## Usage
|
|
67
28
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
```
|
|
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.
|
|
72
32
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
$ curl ... | fx .
|
|
33
|
+
```sh
|
|
34
|
+
echo '{"name": "world"}' | fx 'x => x.name' 'x => `Hello, ${x}!`'
|
|
76
35
|
```
|
|
77
36
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
$ kubectl logs ... -f | fx .message
|
|
81
|
-
```
|
|
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.
|
|
82
39
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
$ fx --life
|
|
40
|
+
```sh
|
|
41
|
+
echo '{"name": "world"}' | fx '.name' '`Hello, ${this}!`'
|
|
86
42
|
```
|
|
87
43
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
See full [documentation](https://github.com/antonmedv/fx/blob/master/DOCS.md).
|
|
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.
|
|
91
46
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
## Related
|
|
47
|
+
```sh
|
|
48
|
+
curl https://api.github.com/repos/antonmedv/fx/commits | fx 'map(x.commit.message)'
|
|
49
|
+
```
|
|
97
50
|
|
|
98
|
-
|
|
99
|
-
|
|
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
|
|
51
|
+
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.
|
|
104
53
|
|
|
54
|
+
```sh
|
|
55
|
+
curl https://api.github.com/repos/kubernetes/kubernetes/issues | fx '.[].labels[].name'
|
|
56
|
+
```
|
|
105
57
|
|
|
106
58
|
## License
|
|
107
59
|
|
|
108
|
-
[MIT](
|
|
60
|
+
[MIT](../LICENSE)
|
package/index.js
CHANGED
|
@@ -1,174 +1,102 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
try {
|
|
10
|
-
require(path.join(os.homedir(), '.fxrc')) // Should be required before config.js usage.
|
|
11
|
-
} catch (err) {
|
|
12
|
-
if (err.code !== 'MODULE_NOT_FOUND') {
|
|
13
|
-
throw err
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const print = require('./print')
|
|
18
|
-
const reduce = require('./reduce')
|
|
19
|
-
const stream = require('./stream')
|
|
20
|
-
|
|
21
|
-
const usage = `
|
|
22
|
-
Usage
|
|
23
|
-
$ fx [code ...]
|
|
24
|
-
|
|
25
|
-
Examples
|
|
26
|
-
$ echo '{"key": "value"}' | fx 'x => x.key'
|
|
27
|
-
value
|
|
28
|
-
|
|
29
|
-
$ echo '{"key": "value"}' | fx .key
|
|
30
|
-
value
|
|
31
|
-
|
|
32
|
-
$ echo '[1,2,3]' | fx 'this.map(x => x * 2)'
|
|
33
|
-
[2, 4, 6]
|
|
34
|
-
|
|
35
|
-
$ echo '{"items": ["one", "two"]}' | fx 'this.items' 'this[1]'
|
|
36
|
-
two
|
|
37
|
-
|
|
38
|
-
$ echo '{"count": 0}' | fx '{...this, count: 1}'
|
|
39
|
-
{"count": 1}
|
|
40
|
-
|
|
41
|
-
$ echo '{"foo": 1, "bar": 2}' | fx ?
|
|
42
|
-
["foo", "bar"]
|
|
43
|
-
|
|
44
|
-
`
|
|
45
|
-
|
|
46
|
-
const {stdin, stdout, stderr} = process
|
|
47
|
-
const args = process.argv.slice(2)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
void function main() {
|
|
51
|
-
stdin.setEncoding('utf8')
|
|
1
|
+
void async function main() {
|
|
2
|
+
const process = await import('node:process')
|
|
3
|
+
let input = ''
|
|
4
|
+
process.stdin.setEncoding('utf8')
|
|
5
|
+
for await (const chunk of process.stdin)
|
|
6
|
+
input += chunk
|
|
7
|
+
const args = process.argv.slice(2)
|
|
52
8
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
9
|
+
let json
|
|
10
|
+
try {
|
|
11
|
+
json = JSON.parse(input)
|
|
12
|
+
} catch (err) {
|
|
13
|
+
try {
|
|
14
|
+
json = eval(`(${input})`)
|
|
15
|
+
} catch (_) {
|
|
16
|
+
process.stderr.write(`Invalid JSON: ${err.message}\n`)
|
|
17
|
+
process.exit(1)
|
|
18
|
+
}
|
|
56
19
|
}
|
|
57
20
|
|
|
58
|
-
|
|
21
|
+
let i, code, output = json
|
|
22
|
+
for ([i, code] of args.entries()) try {
|
|
23
|
+
output = transform(output, code)
|
|
24
|
+
} catch (err) {
|
|
25
|
+
printErr(err)
|
|
26
|
+
process.exit(1)
|
|
27
|
+
}
|
|
59
28
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
29
|
+
if (typeof output === 'undefined')
|
|
30
|
+
process.stderr.write('undefined\n')
|
|
31
|
+
else if (typeof output === 'string')
|
|
32
|
+
console.log(output)
|
|
33
|
+
else
|
|
34
|
+
console.log(JSON.stringify(output, null, 2))
|
|
35
|
+
|
|
36
|
+
function printErr(err) {
|
|
37
|
+
let pre = args.slice(0, i).join(' ')
|
|
38
|
+
let post = args.slice(i + 1).join(' ')
|
|
39
|
+
if (pre.length > 20) pre = '...' + pre.substring(pre.length - 20)
|
|
40
|
+
if (post.length > 20) post = post.substring(0, 20) + '...'
|
|
41
|
+
process.stderr.write(
|
|
42
|
+
`\n ${pre} ${code} ${post}\n` +
|
|
43
|
+
` ${' '.repeat(pre.length + 1)}${'^'.repeat(code.length)}\n` +
|
|
44
|
+
`\n${err.stack || err}\n`
|
|
45
|
+
)
|
|
46
|
+
}
|
|
66
47
|
}()
|
|
67
48
|
|
|
49
|
+
function transform(json, code) {
|
|
50
|
+
if ('.' === code)
|
|
51
|
+
return json
|
|
68
52
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (input === '') {
|
|
73
|
-
if (args.length === 0 || (args.length === 1 && (args[0] === '-h' || args[0] === '--help'))) {
|
|
74
|
-
stderr.write(usage)
|
|
75
|
-
process.exit(2)
|
|
76
|
-
}
|
|
77
|
-
if (args.length === 1 && (args[0] === '-v' || args[0] === '--version')) {
|
|
78
|
-
stderr.write(require('./package.json').version + '\n')
|
|
79
|
-
process.exit(2)
|
|
80
|
-
}
|
|
81
|
-
if (args.length === 1 && args[0] === '--life') {
|
|
82
|
-
require('./bang')
|
|
83
|
-
return
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
input = fs.readFileSync(args[0]).toString('utf8')
|
|
87
|
-
filename = path.basename(args[0])
|
|
88
|
-
global.FX_FILENAME = filename
|
|
89
|
-
args.shift()
|
|
90
|
-
}
|
|
53
|
+
if ('?' === code)
|
|
54
|
+
return Object.keys(json)
|
|
91
55
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
printError(e, input)
|
|
97
|
-
process.exit(1)
|
|
98
|
-
}
|
|
56
|
+
if (/^(\.\w*)+\[]/.test(code))
|
|
57
|
+
return eval(`(function () {
|
|
58
|
+
return (${fold(code.split('[]'))})(this)
|
|
59
|
+
})`).call(json)
|
|
99
60
|
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
61
|
+
if (/^\.\[/.test(code))
|
|
62
|
+
return eval(`(function () {
|
|
63
|
+
return this${code.substring(1)}
|
|
64
|
+
})`).call(json)
|
|
104
65
|
|
|
105
|
-
|
|
106
|
-
|
|
66
|
+
if (/^\./.test(code))
|
|
67
|
+
return eval(`(function () {
|
|
68
|
+
return this${code}
|
|
69
|
+
})`).call(json)
|
|
107
70
|
|
|
108
|
-
|
|
109
|
-
|
|
71
|
+
if (/^map\(.+?\)$/.test(code))
|
|
72
|
+
return eval(`(function () {
|
|
73
|
+
return this.map(x => apply(x, ${code.substring(4, code.length - 1)}))
|
|
74
|
+
})`).call(json)
|
|
110
75
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
} catch (e) {
|
|
115
|
-
if (e === std.skip) {
|
|
116
|
-
return
|
|
117
|
-
}
|
|
118
|
-
stderr.write(`${snippet(i, code)}\n${e.stack || e}\n`)
|
|
119
|
-
process.exit(1)
|
|
120
|
-
}
|
|
121
|
-
}
|
|
76
|
+
const fn = eval(`(function () {
|
|
77
|
+
return ${code}
|
|
78
|
+
})`).call(json)
|
|
122
79
|
|
|
123
|
-
|
|
124
|
-
stderr.write('undefined\n')
|
|
125
|
-
} else if (typeof output === 'string') {
|
|
126
|
-
console.log(output)
|
|
127
|
-
} else {
|
|
128
|
-
const [text] = print(output)
|
|
129
|
-
console.log(text)
|
|
130
|
-
}
|
|
80
|
+
return apply(json, fn)
|
|
131
81
|
}
|
|
132
82
|
|
|
133
|
-
function
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if (pre.length > 20) {
|
|
137
|
-
pre = '...' + pre.substring(pre.length - 20)
|
|
138
|
-
}
|
|
139
|
-
if (post.length > 20) {
|
|
140
|
-
post = post.substring(0, 20) + '...'
|
|
141
|
-
}
|
|
142
|
-
const chalk = require('chalk')
|
|
143
|
-
return `\n ${pre} ${chalk.red.underline(code)} ${post}\n`
|
|
83
|
+
function apply(json, fn) {
|
|
84
|
+
if (typeof fn === 'function') return fn(json)
|
|
85
|
+
return fn
|
|
144
86
|
}
|
|
145
87
|
|
|
146
|
-
function
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (input[i] === '\n') lineNumber++
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
let lines = input
|
|
157
|
-
.substring(start, end)
|
|
158
|
-
.split('\n')
|
|
88
|
+
function fold(s) {
|
|
89
|
+
if (s.length === 1)
|
|
90
|
+
return 'x => x' + s[0]
|
|
91
|
+
let obj = s.shift()
|
|
92
|
+
obj = obj === '.' ? 'x' : 'x' + obj
|
|
93
|
+
return `x => Object.values(${obj}).flatMap(${fold(s)})`
|
|
94
|
+
}
|
|
159
95
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
96
|
+
function uniq(array) {
|
|
97
|
+
return [...new Set(array)]
|
|
98
|
+
}
|
|
164
99
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
for (let line of lines) {
|
|
168
|
-
process.stderr.write(` ${chalk.yellow(lineNumber)} ${line}\n`)
|
|
169
|
-
lineNumber++
|
|
170
|
-
}
|
|
171
|
-
process.stderr.write(`\n`)
|
|
172
|
-
}
|
|
173
|
-
process.stderr.write(e.toString() + '\n')
|
|
100
|
+
function sort(array) {
|
|
101
|
+
return array.sort()
|
|
174
102
|
}
|
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": "24.1.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
|