diff --git a/.gitignore b/.gitignore index eeaf59e..6866b93 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ node_modules /yarn.lock +package-lock.json +.idea diff --git a/.travis.yml b/.travis.yml index 97bccea..1443eb4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,4 @@ language: node_js node_js: - - "0.12" - - "0.11" - - "0.10" - - "iojs" + - "12" + - "10" diff --git a/README.md b/README.md index b1110c2..b3f6c80 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,11 @@ through a JMESPath expression. Using jmespath.js is really easy. There's a single function you use, `jmespath.search`: +```js +var jmespath = require('jmespath'); +jmespath.search({foo: {bar: {baz: [0, 1, 2, 3, 4]}}}, "foo.bar.baz[2]") -``` -> var jmespath = require('jmespath'); -> jmespath.search({foo: {bar: {baz: [0, 1, 2, 3, 4]}}}, "foo.bar.baz[2]") -2 +// output = 2 ``` In the example we gave the ``search`` function input data of @@ -25,20 +25,61 @@ the expression against the input data to produce the result ``2``. The JMESPath language can do a lot more than select an element from a list. Here are a few more examples: -``` -> jmespath.search({foo: {bar: {baz: [0, 1, 2, 3, 4]}}}, "foo.bar") -{ baz: [ 0, 1, 2, 3, 4 ] } +```js +jmespath.search({foo: {bar: {baz: [0, 1, 2, 3, 4]}}}, "foo.bar") -> jmespath.search({"foo": [{"first": "a", "last": "b"}, +// { baz: [ 0, 1, 2, 3, 4 ] } + +jmespath.search({"foo": [{"first": "a", "last": "b"}, {"first": "c", "last": "d"}]}, "foo[*].first") -[ 'a', 'c' ] -> jmespath.search({"foo": [{"age": 20}, {"age": 25}, +// [ 'a', 'c' ] + +jmespath.search({"foo": [{"age": 20}, {"age": 25}, {"age": 30}, {"age": 35}, {"age": 40}]}, "foo[?age > `30`]") -[ { age: 35 }, { age: 40 } ] + +// [ { age: 35 }, { age: 40 } ] +``` + +## Adding custom functions + +Custom functions can be added to the JMESPath runtime by using the +`decorate()` function: + +```js +var TYPE_NUMBER = 0; +function customFunc(resolvedArgs) { + return resolvedArgs[0] + 99; +} +var extraFunctions = { + custom: {_func: customFunc, _signature: [{types: [TYPE_NUMBER]}]}, +}; +jmespath.decorate(extraFunctions); +``` + +The value returned by the decorate function is a curried function +(takes arguments one at a time) that takes the search expression +first and then the data to search against as the second parameter: + +```js +var value = jmespath.decorate(extraFunctions)('custom(`1`)')({}) +// value = 100 +``` + +Because the return value from `decorate()` is a curried function +the result of compiling the expression can be cached and run +multiple times against different data: + +```js +var expr = jmespath.decorate({})('a'); +// expr is now a cached compiled version of the search expression +var value = expr({ a: 1 }); +assert.strictEqual(value, 1); +value = expr({ a: 2 }); +assert.strictEqual(value, 2); ``` ## More Resources diff --git a/artifacts/jmespath.min.js b/artifacts/jmespath.min.js index ae76a6d..c88b550 100644 --- a/artifacts/jmespath.min.js +++ b/artifacts/jmespath.min.js @@ -1,2 +1,2 @@ -/*! jmespath 2016-03-22 */ -!function(a){"use strict";function b(a){return null!==a?"[object Array]"===Object.prototype.toString.call(a):!1}function c(a){return null!==a?"[object Object]"===Object.prototype.toString.call(a):!1}function d(a,e){if(a===e)return!0;var f=Object.prototype.toString.call(a);if(f!==Object.prototype.toString.call(e))return!1;if(b(a)===!0){if(a.length!==e.length)return!1;for(var g=0;g="a"&&"z">=a||a>="A"&&"Z">=a||"_"===a}function h(a){return a>="0"&&"9">=a||"-"===a}function i(a){return a>="a"&&"z">=a||a>="A"&&"Z">=a||a>="0"&&"9">=a||"_"===a}function j(){}function k(){}function l(a){this.runtime=a}function m(a){this.a=a,this.functionTable={abs:{b:this.c,d:[{types:[r]}]},avg:{b:this.e,d:[{types:[z]}]},ceil:{b:this.f,d:[{types:[r]}]},contains:{b:this.g,d:[{types:[t,u]},{types:[s]}]},ends_with:{b:this.h,d:[{types:[t]},{types:[t]}]},floor:{b:this.i,d:[{types:[r]}]},length:{b:this.j,d:[{types:[t,u,v]}]},map:{b:this.k,d:[{types:[x]},{types:[u]}]},max:{b:this.l,d:[{types:[z,A]}]},merge:{b:this.m,d:[{types:[v],variadic:!0}]},max_by:{b:this.n,d:[{types:[u]},{types:[x]}]},sum:{b:this.o,d:[{types:[z]}]},starts_with:{b:this.p,d:[{types:[t]},{types:[t]}]},min:{b:this.q,d:[{types:[z,A]}]},min_by:{b:this.r,d:[{types:[u]},{types:[x]}]},type:{b:this.s,d:[{types:[s]}]},keys:{b:this.t,d:[{types:[v]}]},values:{b:this.u,d:[{types:[v]}]},sort:{b:this.v,d:[{types:[A,z]}]},sort_by:{b:this.w,d:[{types:[u]},{types:[x]}]},join:{b:this.x,d:[{types:[t]},{types:[A]}]},reverse:{b:this.y,d:[{types:[t,u]}]},to_array:{b:this.z,d:[{types:[s]}]},to_string:{b:this.A,d:[{types:[s]}]},to_number:{b:this.B,d:[{types:[s]}]},not_null:{b:this.C,d:[{types:[s],variadic:!0}]}}}function n(a){var b=new k,c=b.parse(a);return c}function o(a){var b=new j;return b.tokenize(a)}function p(a,b){var c=new k,d=new m,e=new l(d);d.a=e;var f=c.parse(b);return e.search(f,a)}var q;q="function"==typeof String.prototype.trimLeft?function(a){return a.trimLeft()}:function(a){return a.match(/^\s*(.*)/)[1]};var r=0,s=1,t=2,u=3,v=4,w=5,x=6,y=7,z=8,A=9,B="EOF",C="UnquotedIdentifier",D="QuotedIdentifier",E="Rbracket",F="Rparen",G="Comma",H="Colon",I="Rbrace",J="Number",K="Current",L="Expref",M="Pipe",N="Or",O="And",P="EQ",Q="GT",R="LT",S="GTE",T="LTE",U="NE",V="Flatten",W="Star",X="Filter",Y="Dot",Z="Not",$="Lbrace",_="Lbracket",aa="Lparen",ba="Literal",ca={".":Y,"*":W,",":G,":":H,"{":$,"}":I,"]":E,"(":aa,")":F,"@":K},da={"<":!0,">":!0,"=":!0,"!":!0},ea={" ":!0," ":!0,"\n":!0};j.prototype={tokenize:function(a){var b=[];this.D=0;for(var c,d,e;this.D"===c?"="===a[this.D]?(this.D++,{type:S,value:">=",start:b}):{type:Q,value:">",start:b}:"="===c&&"="===a[this.D]?(this.D++,{type:P,value:"==",start:b}):void 0},J:function(a){this.D++;for(var b,c=this.D,d=a.length;"`"!==a[this.D]&&this.D=0)return!0;if(c.indexOf(a)>=0)return!0;if(!(d.indexOf(a[0])>=0))return!1;try{return JSON.parse(a),!0}catch(e){return!1}}};var fa={};fa[B]=0,fa[C]=0,fa[D]=0,fa[E]=0,fa[F]=0,fa[G]=0,fa[I]=0,fa[J]=0,fa[K]=0,fa[L]=0,fa[M]=1,fa[N]=2,fa[O]=3,fa[P]=5,fa[Q]=5,fa[R]=5,fa[S]=5,fa[T]=5,fa[U]=5,fa[V]=9,fa[W]=20,fa[X]=21,fa[Y]=40,fa[Z]=45,fa[$]=50,fa[_]=55,fa[aa]=60,k.prototype={parse:function(a){this.M(a),this.index=0;var b=this.expression(0);if(this.N(0)!==B){var c=this.O(0),d=new Error("Unexpected token type: "+c.type+", value: "+c.value);throw d.name="ParserError",d}return b},M:function(a){var b=new j,c=b.tokenize(a);c.push({type:B,value:"",start:a.length}),this.tokens=c},expression:function(a){var b=this.O(0);this.P();for(var c=this.nud(b),d=this.N(0);ab;){if(c===H)b++,this.P();else{if(c!==J){var d=this.N(0),e=new Error("Syntax error, unexpected token: "+d.value+"("+d.type+")");throw e.name="Parsererror",e}a[b]=this.O(0).value,this.P()}c=this.N(0)}return this.V(E),{type:"Slice",children:a}},Y:function(a,b){var c=this.expression(fa[b]);return{type:"Comparator",name:b,children:[a,c]}},X:function(a){var b=this.N(0),c=[C,D,W];return c.indexOf(b)>=0?this.expression(a):b===_?(this.V(_),this.U()):b===$?(this.V($),this.R()):void 0},Q:function(a){var b;if(fa[this.N(0)]<10)b={type:"Identity"};else if(this.N(0)===_)b=this.expression(a);else if(this.N(0)===X)b=this.expression(a);else{if(this.N(0)!==Y){var c=this.O(0),d=new Error("Sytanx error, unexpected token: "+c.value+"("+c.type+")");throw d.name="ParserError",d}this.V(Y),b=this.X(a)}return b},U:function(){for(var a=[];this.N(0)!==E;){var b=this.expression(0);if(a.push(b),this.N(0)===G&&(this.V(G),this.N(0)===E))throw new Error("Unexpected token Rbracket")}return this.V(E),{type:"MultiSelectList",children:a}},R:function(){for(var a,b,c,d,e=[],f=[C,D];;){if(a=this.O(0),f.indexOf(a.type)<0)throw new Error("Expecting an identifier token, got: "+a.type);if(b=a.value,this.P(),this.V(H),c=this.expression(0),d={type:"KeyValuePair",name:b,value:c},e.push(d),this.N(0)===G)this.V(G);else if(this.N(0)===I){this.V(I);break}}return{type:"MultiSelectHash",children:e}}},l.prototype={search:function(a,b){return this.visit(a,b)},visit:function(a,g){var h,i,j,k,l,m,n,o,p,q;switch(a.type){case"Field":return null===g?null:c(g)?(m=g[a.name],void 0===m?null:m):null;case"Subexpression":for(j=this.visit(a.children[0],g),q=1;qr&&(r=g.length+r),j=g[r],void 0===j&&(j=null),j;case"Slice":if(!b(g))return null;var s=a.children.slice(0),t=this.computeSliceParams(g.length,s),u=t[0],v=t[1],w=t[2];if(j=[],w>0)for(q=u;v>q;q+=w)j.push(g[q]);else for(q=u;q>v;q+=w)j.push(g[q]);return j;case"Projection":var x=this.visit(a.children[0],g);if(!b(x))return null;for(p=[],q=0;ql;break;case S:j=k>=l;break;case R:j=l>k;break;case T:j=l>=k;break;default:throw new Error("Unknown comparator: "+a.name)}return j;case V:var C=this.visit(a.children[0],g);if(!b(C))return null;var D=[];for(q=0;qe?!0:!1;return c=null===c?h?a-1:0:this.capSliceRange(a,c,e),d=null===d?h?-1:a:this.capSliceRange(a,d,e),f[0]=c,f[1]=d,f[2]=e,f},capSliceRange:function(a,b,c){return 0>b?(b+=a,0>b&&(b=0>c?-1:0)):b>=a&&(b=0>c?a-1:a),b}},m.prototype={callFunction:function(a,b){var c=this.functionTable[a];if(void 0===c)throw new Error("Unknown function: "+a+"()");return this.$(a,b,c.d),c.b.call(this,b)},$:function(a,b,c){var d;if(c[c.length-1].variadic){if(b.length=0;e--)d+=c[e];return d}var f=a[0].slice(0);return f.reverse(),f},c:function(a){return Math.abs(a[0])},f:function(a){return Math.ceil(a[0])},e:function(a){for(var b=0,c=a[0],d=0;d=0},i:function(a){return Math.floor(a[0])},j:function(a){return c(a[0])?Object.keys(a[0]).length:a[0].length},k:function(a){for(var b=[],c=this.a,d=a[0],e=a[1],f=0;f0){var b=this._(a[0][0]);if(b===r)return Math.max.apply(Math,a[0]);for(var c=a[0],d=c[0],e=1;e0){var b=this._(a[0][0]);if(b===r)return Math.min.apply(Math,a[0]);for(var c=a[0],d=c[0],e=1;eh?1:h>g?-1:a[0]-b[0]});for(var i=0;ig&&(g=c,b=e[h]);return b},r:function(a){for(var b,c,d=a[1],e=a[0],f=this.createKeyFunction(d,[r,t]),g=1/0,h=0;hc&&(g=c,b=e[h]);return b},createKeyFunction:function(a,b){var c=this,d=this.a,e=function(e){var f=d.visit(a,e);if(b.indexOf(c._(f))<0){var g="TypeError: expected one of "+b+", received "+c._(f);throw new Error(g)}return f};return e}},a.tokenize=o,a.compile=n,a.search=p,a.strictDeepEqual=d}("undefined"==typeof exports?this.jmespath={}:exports); \ No newline at end of file +/*! jmespath 2020-02-28 */ +!function(a){"use strict";function b(a){return null!==a&&"[object Array]"===Object.prototype.toString.call(a)}function c(a){return null!==a&&"[object Object]"===Object.prototype.toString.call(a)}function d(a,e){if(a===e)return!0;var f=Object.prototype.toString.call(a);if(f!==Object.prototype.toString.call(e))return!1;if(b(a)===!0){if(a.length!==e.length)return!1;for(var g=0;g="a"&&a<="z"||a>="A"&&a<="Z"||"_"===a}function h(a){return a>="0"&&a<="9"||"-"===a}function i(a){return a>="a"&&a<="z"||a>="A"&&a<="Z"||a>="0"&&a<="9"||"_"===a}function j(){}function k(){}function l(a){this.runtime=a}function m(a){this.a=a,this.functionTable={abs:{b:this.c,d:[{types:[s]}]},avg:{b:this.e,d:[{types:[A]}]},ceil:{b:this.f,d:[{types:[s]}]},contains:{b:this.g,d:[{types:[u,v]},{types:[t]}]},ends_with:{b:this.h,d:[{types:[u]},{types:[u]}]},floor:{b:this.i,d:[{types:[s]}]},length:{b:this.j,d:[{types:[u,v,w]}]},map:{b:this.k,d:[{types:[y]},{types:[v]}]},max:{b:this.l,d:[{types:[A,B]}]},merge:{b:this.m,d:[{types:[w],variadic:!0}]},max_by:{b:this.n,d:[{types:[v]},{types:[y]}]},sum:{b:this.o,d:[{types:[A]}]},starts_with:{b:this.p,d:[{types:[u]},{types:[u]}]},min:{b:this.q,d:[{types:[A,B]}]},min_by:{b:this.r,d:[{types:[v]},{types:[y]}]},type:{b:this.s,d:[{types:[t]}]},keys:{b:this.t,d:[{types:[w]}]},values:{b:this.u,d:[{types:[w]}]},sort:{b:this.v,d:[{types:[B,A]}]},sort_by:{b:this.w,d:[{types:[v]},{types:[y]}]},join:{b:this.x,d:[{types:[u]},{types:[B]}]},reverse:{b:this.y,d:[{types:[u,v]}]},to_array:{b:this.z,d:[{types:[t]}]},to_string:{b:this.A,d:[{types:[t]}]},to_number:{b:this.B,d:[{types:[t]}]},not_null:{b:this.C,d:[{types:[t],variadic:!0}]}}}function n(a){var b=new k,c=b.parse(a);return c}function o(a){var b=new j;return b.tokenize(a)}function p(a,b){return q({})(b)(a)}function q(a){var b=new k,c=new m;Object.assign(c.functionTable,a);var d=new l(c);return c.a=d,function(a){var c=b.parse(a);return function(a){return d.search(c,a)}}}var r;r="function"==typeof String.prototype.trimLeft?function(a){return a.trimLeft()}:function(a){return a.match(/^\s*(.*)/)[1]};var s=0,t=1,u=2,v=3,w=4,x=5,y=6,z=7,A=8,B=9,C={0:"number",1:"any",2:"string",3:"array",4:"object",5:"boolean",6:"expression",7:"null",8:"Array",9:"Array"},D="EOF",E="UnquotedIdentifier",F="QuotedIdentifier",G="Rbracket",H="Rparen",I="Comma",J="Colon",K="Rbrace",L="Number",M="Current",N="Root",O="Expref",P="Pipe",Q="Or",R="And",S="EQ",T="GT",U="LT",V="GTE",W="LTE",X="NE",Y="Flatten",Z="Star",$="Filter",_="Dot",aa="Not",ba="Lbrace",ca="Lbracket",da="Lparen",ea="Literal",fa={".":_,"*":Z,",":I,":":J,"{":ba,"}":K,"]":G,"(":da,")":H,"@":M,$:N},ga={"<":!0,">":!0,"=":!0,"!":!0},ha={" ":!0,"\t":!0,"\r":!0,"\n":!0};j.prototype={tokenize:function(a){var b=[];this.D=0;for(var c,d,e;this.D"===c?"="===a[this.D]?(this.D++,{type:V,value:">=",start:b}):{type:T,value:">",start:b}:"="===c&&"="===a[this.D]?(this.D++,{type:S,value:"==",start:b}):void 0},J:function(a){this.D++;for(var b,c=this.D,d=a.length;"`"!==a[this.D]&&this.D=0)return!0;if(c.indexOf(a)>=0)return!0;if(!(d.indexOf(a[0])>=0))return!1;try{return JSON.parse(a),!0}catch(e){return!1}}};var ia={};ia[D]=0,ia[E]=0,ia[F]=0,ia[G]=0,ia[H]=0,ia[I]=0,ia[K]=0,ia[L]=0,ia[M]=0,ia[N]=0,ia[O]=0,ia[P]=1,ia[Q]=2,ia[R]=3,ia[S]=5,ia[T]=5,ia[U]=5,ia[V]=5,ia[W]=5,ia[X]=5,ia[Y]=9,ia[Z]=20,ia[$]=21,ia[_]=40,ia[aa]=45,ia[ba]=50,ia[ca]=55,ia[da]=60,k.prototype={parse:function(a){this.M(a),this.index=0;var b=this.expression(0);if(this.N(0)!==D){var c=this.O(0),d=new Error("Unexpected token type: "+c.type+", value: "+c.value);throw d.name="ParserError",d}return b},M:function(a){var b=new j,c=b.tokenize(a);c.push({type:D,value:"",start:a.length}),this.tokens=c},expression:function(a){var b=this.O(0);this.P();for(var c=this.nud(b),d=this.N(0);a=0?this.expression(a):b===ca?(this.V(ca),this.U()):b===ba?(this.V(ba),this.R()):void 0},Q:function(a){var b;if(ia[this.N(0)]<10)b={type:"Identity"};else if(this.N(0)===ca)b=this.expression(a);else if(this.N(0)===$)b=this.expression(a);else{if(this.N(0)!==_){var c=this.O(0),d=new Error("Syntax error, unexpected token: "+c.value+"("+c.type+")");throw d.name="ParserError",d}this.V(_),b=this.X(a)}return b},U:function(){for(var a=[];this.N(0)!==G;){var b=this.expression(0);if(a.push(b),this.N(0)===I&&(this.V(I),this.N(0)===G))throw new Error("Unexpected token Rbracket")}return this.V(G),{type:"MultiSelectList",children:a}},R:function(){for(var a,b,c,d,e=[],f=[E,F];;){if(a=this.O(0),f.indexOf(a.type)<0)throw new Error("Expecting an identifier token, got: "+a.type);if(b=a.value,this.P(),this.V(J),c=this.expression(0),d={type:"KeyValuePair",name:b,value:c},e.push(d),this.N(0)===I)this.V(I);else if(this.N(0)===K){this.V(K);break}}return{type:"MultiSelectHash",children:e}}},l.prototype={search:function(a,b){return this._=b,this.visit(a,b)},visit:function(a,g){var h,i,j,k,l,m,n,o,p,q;switch(a.type){case"Field":return null!==g&&c(g)?(m=g[a.name],void 0===m?null:m):null;case"Subexpression":for(j=this.visit(a.children[0],g),q=1;q0)for(q=u;qv;q+=w)j.push(g[q]);return j;case"Projection":var x=this.visit(a.children[0],g);if(!b(x))return null;for(p=[],q=0;ql;break;case V:j=k>=l;break;case U:j=k=a&&(b=c<0?a-1:a),b}},m.prototype={callFunction:function(a,b){var c=this.functionTable[a];if(void 0===c)throw new Error("Unknown function: "+a+"()");return this.aa(a,b,c.d),c.b.call(this,b)},aa:function(a,b,c){var d;if(c[c.length-1].variadic){if(b.length=0;e--)d+=c[e];return d}var f=a[0].slice(0);return f.reverse(),f},c:function(a){return Math.abs(a[0])},f:function(a){return Math.ceil(a[0])},e:function(a){for(var b=0,c=a[0],d=0;d=0},i:function(a){return Math.floor(a[0])},j:function(a){return c(a[0])?Object.keys(a[0]).length:a[0].length},k:function(a){for(var b=[],c=this.a,d=a[0],e=a[1],f=0;f0){var b=this.ba(a[0][0]);if(b===s)return Math.max.apply(Math,a[0]);for(var c=a[0],d=c[0],e=1;e0){var b=this.ba(a[0][0]);if(b===s)return Math.min.apply(Math,a[0]);for(var c=a[0],d=c[0],e=1;eh?1:gg&&(g=c,b=e[h]);return b},r:function(a){for(var b,c,d=a[1],e=a[0],f=this.createKeyFunction(d,[s,u]),g=1/0,h=0;h