diff --git a/README.md b/README.md index 1bee78e..6dd012f 100644 --- a/README.md +++ b/README.md @@ -6,19 +6,38 @@ --- Performant JSONPath implementation that focusses on results +**Features** + +- Fast +- Extended syntax support +- Error safe, using a simple Maybe functor under the hood +- Memoized compilation of queries +- 100% code coverage + +**Syntax** + +COMING SOON + **Installation** + ```bash -$npm install --save @f5io/jsonpath +$ npm install --save @f5io/jsonpath ``` or if you have yarn installed on your machine ```bash -$yarn add @f5io/jsonpath +$ yarn add @f5io/jsonpath ``` **Usage** + ```js -var jp = require('@f5io/jsonpath'); -var jsonPathQueryStr = "$..h[?(@.foo>13)]"; -var result = jp(jsonPathQueryStr,jsonObject); +const jp = require('@f5io/jsonpath'); +const jsonPathQueryStr = '$..h[?(@.foo>13)]'; +const result = jp(jsonPathQueryStr,jsonObject); ``` + +**Contributors** + +- Joe Harlow [@f5io](https://github.com/f5io) +- Amit Gupta [@amitguptagql](https://github.com/amitguptagwl) diff --git a/package.json b/package.json index 94eed39..3e70e22 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@f5io/jsonpath", - "version": "1.0.1", + "version": "1.0.2", "description": "Performant JSONPath implementation", "main": "lib/index.js", "scripts": { diff --git a/src/maybe.js b/src/maybe.js index 8d13043..6008693 100644 --- a/src/maybe.js +++ b/src/maybe.js @@ -12,9 +12,9 @@ class Maybe { } get() { return this.value; - } -}; + } +} function maybe(v) { return new Maybe(v); -}; \ No newline at end of file +} diff --git a/src/rules/index.js b/src/rules/index.js index 717ab1d..dfdd35c 100644 --- a/src/rules/index.js +++ b/src/rules/index.js @@ -1,6 +1,6 @@ import tokenizer from '../tokenizer'; import parser from '../parser'; -import { Identity, head, map, isPlainObject } from '../utils'; +import { Identity, head, map, mapFilter, isPlainObject } from '../utils'; const rules = { [1]: { @@ -27,7 +27,7 @@ const rules = { a = a.concat(search(x[k], p)); } return a; - }; + } const next = arr[i + 1]; if (next && next.type === 'prop') @@ -41,12 +41,12 @@ const rules = { parse: function prop(acc, { value }, i, arr) { const prev = arr[i - 1]; if (prev && prev.type === 'recurse') return acc; - + const getProps = x => Array.isArray(x) ? - x.map(y => y[value]) : + mapFilter(y => y[value])(x) : x[value]; - + return acc.concat(map(getProps)); } }, @@ -189,4 +189,4 @@ function getMatch(str) { parse, value: map(mapRes) }; -}; \ No newline at end of file +} diff --git a/src/utils/index.js b/src/utils/index.js index 5da9c02..e8d9cc3 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -15,4 +15,14 @@ export const isPlainObject = o => { if (isObjectObject(o.constructor.prototype) === false) return false; if (o.constructor.prototype.hasOwnProperty('isPrototypeOf') === false) return false; return true; -}; \ No newline at end of file +}; + +export const mapFilter = f => x => { + const output = []; + let xi; + while (xi = x.shift()) { + const result = f(xi); + if (typeof result !== 'undefined') output.push(result); + } + return output; +}; diff --git a/test/change.json b/test/change.json new file mode 100644 index 0000000..eb269a4 --- /dev/null +++ b/test/change.json @@ -0,0 +1,166 @@ +{ + "a": { + "1": "la", + "2": "boo", + "h": [ + { + "foo": [ + 1, + 2, + 3 + ] + }, + { + "foo": [ + 4, + 5, + 6 + ] + }, + { + "foo": 12, + "name": "a" + }, + { + "foo": 13.5, + "name": { + "h": 45 + } + }, + { + "foo": 11.8, + "name": "c" + }, + true, + 123, + [ + 3, + 4, + 5 + ] + ] + }, + "b": { + "1": "la", + "2": "boo", + "h": [ + { + "foo": [ + 1, + 2, + 3 + ] + }, + { + "foo": [ + 4, + 5, + 6 + ] + }, + { + "foo": 12, + "name": "a" + }, + { + "foo": 13.5, + "name": { + "h": 45 + } + }, + { + "foo": 11.8, + "name": "c" + }, + true, + 123, + [ + 3, + 4, + 5 + ] + ] + }, + "c": { + "1": "la", + "2": "boo", + "h": [ + { + "foo": [ + 1, + 2, + 3 + ] + }, + { + "foo": [ + 4, + 5, + 6 + ] + }, + { + "foo": 12, + "name": "a" + }, + { + "foo": 13.5, + "name": { + "h": 45 + } + }, + { + "foo": 11.8, + "name": "c" + }, + true, + 123, + [ + 3, + 4, + 5 + ] + ] + }, + "d": { + "1": "la", + "2": "boo", + "h": [ + { + "foo": [ + 1, + 2, + 3 + ] + }, + { + "foo": [ + 4, + 5, + 6 + ] + }, + { + "foo": 12, + "name": "a" + }, + { + "foo": 13.5, + "name": { + "h": 45 + } + }, + { + "foo": 11.8, + "name": "c" + }, + true, + 123, + [ + 3, + 4, + 5 + ] + ] + } +} diff --git a/test/index.js b/test/index.js index 19b69e1..3bd5d53 100644 --- a/test/index.js +++ b/test/index.js @@ -20,11 +20,11 @@ const measure = (name, fn, ...args) => { return result; }; -const runQueries = (test, queries, expected) => { +const runQueries = (test, queries, expected, d = data) => { test.plan(queries.length); queries.forEach(q => { const qy = measure(`parse: '${q}'`, query, q); - const result = measure(`query: '${q}'`, qy, data); + const result = measure(`query: '${q}'`, qy, d); test.deepEquals(result, expected, `'${q}' should return expected results`); }); }; @@ -270,4 +270,21 @@ test('get bicycle with omember', t => { '$.store.bicycle{"color"}' ]; runQueries(t, queries, expected); -}); \ No newline at end of file +}); + +test('changejs example', t => { + const expected = [ + [ 1, 2, 3 ], [ 4, 5, 6 ], + 12, 13.5, 11.8, + [ 1, 2, 3 ], [ 4, 5, 6 ], + 12, 13.5, 11.8, + [ 1, 2, 3 ], [ 4, 5, 6 ], + 12, 13.5, 11.8, + [ 1, 2, 3 ], [ 4, 5, 6 ], + 12, 13.5, 11.8 + ]; + const queries = [ + '$..h[*].foo' + ]; + runQueries(t, queries, expected, require('./change.json')); +});