diff --git a/README.md b/README.md index e78a5d5..4f2081c 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ $ echo '{"key":"value"}' | fx Use an anonymous function as reducer which gets JSON and processes it: ``` $ echo '{"foo": [{"bar": "value"}]}' | fx 'x => x.foo[0].bar' -"value" +value ``` ### 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: ``` $ 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 @@ -57,7 +66,7 @@ $ echo '{"foo": [{"bar": "value"}]}' | fx 'this.foo[0].bar' You can pass any number of anonymous functions for reducing JSON: ``` $ echo '{"foo": [{"bar": "value"}]}' | fx 'x => x.foo' 'this[0]' 'this.bar' -"value" +value ``` ### Generator diff --git a/index.js b/index.js index ca61078..c60d99c 100755 --- a/index.js +++ b/index.js @@ -10,16 +10,22 @@ const cli = meow(` Examples $ echo '{"key": "value"}' | fx 'x => x.key' - "value" + value $ echo '[1,2,3]' | fx 'this.map(x => x * 2)' [2, 4, 6] $ echo '{"items": ["one", "two"]}' | fx 'this.items' 'this[1]' - "two" + two $ echo '{"count": 0}' | fx '{...this, count: 1}' {"count": 1} + + $ echo '{"foo": 1, "bar": 2}' | fx ? + ["foo", "bar"] + + $ echo '{"key": "value"}' | fx .key + value `) async function main() { @@ -34,6 +40,8 @@ async function main() { if (typeof result === 'undefined') { process.stderr.write('undefined\n') + } else if (typeof result === 'string') { + console.log(result) } else if (process.stdout.isTTY) { console.log(pretty(result)) } else { @@ -45,7 +53,9 @@ function reduce(json, code) { if (/^\w+\s*=>/.test(code)) { const fx = eval(code) return fx(json) - } else if (/yield/.test(code)) { + } + + if (/yield/.test(code)) { const fx = eval(` function fn() { const gen = (function*(){ @@ -55,12 +65,19 @@ function reduce(json, code) { }; fn `) return fx.call(json) - } else if (/^\?$/.test(code)) { + } + + if (/^\?$/.test(code)) { 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) } + + const fx = eval(`function fn() { return ${code} }; fn`) + return fx.call(json) } main() diff --git a/test.js b/test.js index 123ad3f..eadaa8a 100644 --- a/test.js +++ b/test.js @@ -3,26 +3,30 @@ const test = require('ava') const {execSync} = require('child_process') function fx(json, code = '') { - const output = execSync(`echo '${JSON.stringify(json)}' | node index.js ${code}`).toString('utf8') - return JSON.parse(output) + return execSync(`echo '${JSON.stringify(json)}' | node index.js ${code}`).toString('utf8') } 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 => { - 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 => { - 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 => { - 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 => { - 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') })