Add dot feature

js-version
Anton Medvedev 6 years ago
parent 17b30f2622
commit 9bd442da48

@ -40,7 +40,7 @@ $ echo '{"key":"value"}' | fx
Use an anonymous function as reducer which gets JSON and processes it: Use an anonymous function as reducer which gets JSON and processes it:
``` ```
$ echo '{"foo": [{"bar": "value"}]}' | fx 'x => x.foo[0].bar' $ echo '{"foo": [{"bar": "value"}]}' | fx 'x => x.foo[0].bar'
"value" value
``` ```
### This Binding ### This Binding
@ -49,7 +49,16 @@ If you don't pass anonymous function `param => ...`, code will be automatically
And you can get access to JSON by `this` keyword: And you can get access to JSON by `this` keyword:
``` ```
$ echo '{"foo": [{"bar": "value"}]}' | fx 'this.foo[0].bar' $ echo '{"foo": [{"bar": "value"}]}' | fx 'this.foo[0].bar'
"value" value
```
### Dot
It is possible to omit `this` keyword:
```
$ echo '{"foo": [{"bar": "value"}]}' | fx .foo[0].bar
value
``` ```
### Chain ### Chain
@ -57,7 +66,7 @@ $ echo '{"foo": [{"bar": "value"}]}' | fx 'this.foo[0].bar'
You can pass any number of anonymous functions for reducing JSON: You can pass any number of anonymous functions for reducing JSON:
``` ```
$ echo '{"foo": [{"bar": "value"}]}' | fx 'x => x.foo' 'this[0]' 'this.bar' $ echo '{"foo": [{"bar": "value"}]}' | fx 'x => x.foo' 'this[0]' 'this.bar'
"value" value
``` ```
### Generator ### Generator

@ -10,16 +10,22 @@ const cli = meow(`
Examples Examples
$ echo '{"key": "value"}' | fx 'x => x.key' $ echo '{"key": "value"}' | fx 'x => x.key'
"value" value
$ echo '[1,2,3]' | fx 'this.map(x => x * 2)' $ echo '[1,2,3]' | fx 'this.map(x => x * 2)'
[2, 4, 6] [2, 4, 6]
$ echo '{"items": ["one", "two"]}' | fx 'this.items' 'this[1]' $ echo '{"items": ["one", "two"]}' | fx 'this.items' 'this[1]'
"two" two
$ echo '{"count": 0}' | fx '{...this, count: 1}' $ echo '{"count": 0}' | fx '{...this, count: 1}'
{"count": 1} {"count": 1}
$ echo '{"foo": 1, "bar": 2}' | fx ?
["foo", "bar"]
$ echo '{"key": "value"}' | fx .key
value
`) `)
async function main() { async function main() {
@ -34,6 +40,8 @@ async function main() {
if (typeof result === 'undefined') { if (typeof result === 'undefined') {
process.stderr.write('undefined\n') process.stderr.write('undefined\n')
} else if (typeof result === 'string') {
console.log(result)
} else if (process.stdout.isTTY) { } else if (process.stdout.isTTY) {
console.log(pretty(result)) console.log(pretty(result))
} else { } else {
@ -45,7 +53,9 @@ function reduce(json, code) {
if (/^\w+\s*=>/.test(code)) { if (/^\w+\s*=>/.test(code)) {
const fx = eval(code) const fx = eval(code)
return fx(json) return fx(json)
} else if (/yield/.test(code)) { }
if (/yield/.test(code)) {
const fx = eval(` const fx = eval(`
function fn() { function fn() {
const gen = (function*(){ const gen = (function*(){
@ -55,12 +65,19 @@ function reduce(json, code) {
}; fn }; fn
`) `)
return fx.call(json) return fx.call(json)
} else if (/^\?$/.test(code)) { }
if (/^\?$/.test(code)) {
return Object.keys(json) return Object.keys(json)
} else { }
const fx = eval(`function fn() { return ${code} }; fn`)
if (/^\./.test(code)) {
const fx = eval(`function fn() { return ${code === '.' ? 'this' : 'this' + code} }; fn`)
return fx.call(json) return fx.call(json)
} }
const fx = eval(`function fn() { return ${code} }; fn`)
return fx.call(json)
} }
main() main()

@ -3,26 +3,30 @@ const test = require('ava')
const {execSync} = require('child_process') const {execSync} = require('child_process')
function fx(json, code = '') { function fx(json, code = '') {
const output = execSync(`echo '${JSON.stringify(json)}' | node index.js ${code}`).toString('utf8') return execSync(`echo '${JSON.stringify(json)}' | node index.js ${code}`).toString('utf8')
return JSON.parse(output)
} }
test('pass', t => { test('pass', t => {
t.deepEqual(fx([{"greeting": "hello world"}]), [{"greeting": "hello world"}]) const r = fx([{"greeting": "hello world"}])
t.deepEqual(JSON.parse(r), [{"greeting": "hello world"}])
}) })
test('anon func', t => { test('anon func', t => {
t.deepEqual(fx({"key": "value"}, "'x => x.key'"), 'value') const r = fx({"key": "value"}, "'x => x.key'")
t.deepEqual(r, 'value\n')
}) })
test('this bind', t => { test('this bind', t => {
t.deepEqual(fx([1, 2, 3, 4, 5], "'this.map(x => x * this.length)'"), [5, 10, 15, 20, 25]) const r = fx([1, 2, 3, 4, 5], "'this.map(x => x * this.length)'")
t.deepEqual(JSON.parse(r), [5, 10, 15, 20, 25])
}) })
test('generator', t => { test('generator', t => {
t.deepEqual(fx([1, 2, 3, 4, 5], "'for (let i of this) if (i % 2 == 0) yield i'"), [2, 4]) const r = fx([1, 2, 3, 4, 5], "'for (let i of this) if (i % 2 == 0) yield i'")
t.deepEqual(JSON.parse(r), [2, 4])
}) })
test('chain', t => { test('chain', t => {
t.deepEqual(fx({"items": ["foo", "bar"]}, "'this.items' 'yield* this' 'x => x[1]'"), 'bar') const r = fx({"items": ["foo", "bar"]}, "'this.items' 'yield* this' 'x => x[1]'")
t.deepEqual(r, 'bar\n')
}) })

Loading…
Cancel
Save