From 0188ab88ac363749f1b6c7ba87718245940f45fa Mon Sep 17 00:00:00 2001 From: Mo Morsi Date: Thu, 21 Jun 2018 16:47:47 -0400 Subject: [PATCH] Add generic scope support for expressions. Variables and funcations can now be injected into the expression scope like so: jsonpath.scope({foo:'bar',parseInt:parseInt}) Thus the client can incorporate builtin or custom methods in jsonpath expressions: $..[?(parseInt(@.Amount) > 0)] --- lib/handlers.js | 21 ++++++++++++++------- lib/index.js | 4 ++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/handlers.js b/lib/handlers.js index c00e6b0..635d28e 100755 --- a/lib/handlers.js +++ b/lib/handlers.js @@ -10,6 +10,11 @@ var Handlers = function() { Handlers.prototype.initialize = function() { this.traverse = traverser(true); this.descend = traverser(); + this._scope = {}; +} + +Handlers.prototype.scope = function(_scope){ + this._scope = _scope; } Handlers.prototype.keys = Object.keys; @@ -115,8 +120,9 @@ Handlers.prototype._fns = { var src = component.expression.value.slice(2, -1); var ast = aesprim.parse(src).body[0].expression; + var _scope = this._scope; var passable = function(key, value) { - return evaluate(ast, { '@': value }); + return evaluate(ast, Object.assign({ '@': value }, _scope)); } return this.descend(partial, null, passable, count); @@ -129,8 +135,9 @@ Handlers.prototype._fns = { var src = component.expression.value.slice(2, -1); var ast = aesprim.parse(src).body[0].expression; + var _scope = this._scope; var passable = function(key, value) { - return evaluate(ast, { '@': value }); + return evaluate(ast, Object.assign({ '@': value }, _scope)); } return this.traverse(partial, null, passable, count); @@ -138,17 +145,17 @@ Handlers.prototype._fns = { 'subscript-child-script_expression': function(component, partial) { var exp = component.expression.value.slice(1, -1); - return eval_recurse(partial, exp, '$[{{value}}]'); + return eval_recurse(partial, exp, '$[{{value}}]', this._scope); }, 'member-child-script_expression': function(component, partial) { var exp = component.expression.value.slice(1, -1); - return eval_recurse(partial, exp, '$.{{value}}'); + return eval_recurse(partial, exp, '$.{{value}}', this._scope); }, 'member-descendant-script_expression': function(component, partial) { var exp = component.expression.value.slice(1, -1); - return eval_recurse(partial, exp, '$..value'); + return eval_recurse(partial, exp, '$..value', this._scope); } }; @@ -159,11 +166,11 @@ Handlers.prototype._fns['member-descendant-numeric_literal'] = Handlers.prototype._fns['subscript-descendant-string_literal'] = Handlers.prototype._fns['member-descendant-identifier']; -function eval_recurse(partial, src, template) { +function eval_recurse(partial, src, template, _scope) { var jp = require('./index'); var ast = aesprim.parse(src).body[0].expression; - var value = evaluate(ast, { '@': partial.value }); + var value = evaluate(ast, Object.assign({ '@': partial.value }, _scope)); var path = template.replace(/\{\{\s*value\s*\}\}/g, value); var results = jp.nodes(partial.value, path); diff --git a/lib/index.js b/lib/index.js index 8f5a832..f3d65fc 100755 --- a/lib/index.js +++ b/lib/index.js @@ -12,6 +12,10 @@ JSONPath.prototype.initialize = function() { this.handlers = new Handlers(); }; +JSONPath.prototype.scope = function(scope){ + this.handlers.scope(scope); +} + JSONPath.prototype.parse = function(string) { assert.ok(_is_string(string), "we need a path"); return this.parser.parse(string);