├── .gitignore ├── .jscsrc ├── .jshintrc ├── .travis.yml ├── Dockerfile ├── Gruntfile.js ├── LICENSE ├── README.md ├── bin └── generate_parser.js ├── fig.yml ├── generated └── parser.js ├── index.js ├── jsonpath.js ├── jsonpath.min.js ├── lib ├── aesprim.js ├── dict.js ├── grammar.js ├── handlers.js ├── index.js ├── parser.js └── slice.js ├── package.json └── test ├── data └── store.json ├── lessons.js ├── parse.js ├── query.js ├── slice.js ├── stringify.js └── sugar.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | generated/aesprim-browser.js 3 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "disallowSpacesInNamedFunctionExpression": { 3 | "beforeOpeningRoundBrace": true 4 | }, 5 | "disallowSpacesInFunctionExpression": { 6 | "beforeOpeningRoundBrace": true 7 | }, 8 | "disallowSpacesInAnonymousFunctionExpression": { 9 | "beforeOpeningRoundBrace": true 10 | }, 11 | "disallowSpacesInFunctionDeclaration": { 12 | "beforeOpeningRoundBrace": true 13 | }, 14 | "disallowEmptyBlocks": true, 15 | "disallowSpacesInsideParentheses": true, 16 | "disallowQuotedKeysInObjects": true, 17 | "disallowSpaceAfterObjectKeys": true, 18 | "disallowSpaceAfterPrefixUnaryOperators": true, 19 | "disallowSpaceBeforePostfixUnaryOperators": true, 20 | "disallowSpaceBeforeBinaryOperators": [ 21 | "," 22 | ], 23 | "disallowMixedSpacesAndTabs": true, 24 | "disallowTrailingWhitespace": true, 25 | "disallowTrailingComma": true, 26 | "disallowYodaConditions": true, 27 | "disallowKeywords": [ "with" ], 28 | "disallowMultipleLineBreaks": true, 29 | "requireSpaceBeforeBlockStatements": true, 30 | "requireParenthesesAroundIIFE": true, 31 | "requireSpacesInConditionalExpression": true, 32 | "disallowMultipleVarDecl": true, 33 | "requireBlocksOnNewline": 1, 34 | "requireCommaBeforeLineBreak": true, 35 | "requireSpaceBeforeBinaryOperators": true, 36 | "requireSpaceAfterBinaryOperators": true, 37 | "requireLineFeedAtFileEnd": true, 38 | "requireCapitalizedConstructors": true, 39 | "requireDotNotation": true, 40 | "requireSpacesInForStatement": true, 41 | "requireCurlyBraces": [ 42 | "do" 43 | ], 44 | "requireSpaceAfterKeywords": [ 45 | "if", 46 | "else", 47 | "for", 48 | "while", 49 | "do", 50 | "switch", 51 | "case", 52 | "return", 53 | "try", 54 | "catch", 55 | "typeof" 56 | ], 57 | "safeContextKeyword": "self", 58 | "validateLineBreaks": "LF", 59 | "validateIndentation": 2 60 | } 61 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "undef": true, 4 | "unused": true, 5 | "lastsemic": true, 6 | "-W058": false, /* don't require parentheses for no-arg constructors */ 7 | "-W054": false, /* use Function constructor responsibly */ 8 | "-W033": false /* let jscs deal with semicolons */ 9 | } 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:0.11-onbuild 2 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.initConfig({ 3 | pkg: grunt.file.readJSON('package.json'), 4 | outputFolder: ".", 5 | 6 | browserify: { 7 | main: { 8 | src: ['index.js'], 9 | dest: '<%= outputFolder %>/<%= pkg.name %>.js', 10 | options: { 11 | browserifyOptions: { standalone: '<%= pkg.name %>' }, 12 | banner: '/*! <%= pkg.name %> <%= pkg.version %> */\n', 13 | alias: { 14 | "jsonpath": "./index.js" 15 | }, 16 | require: [ 17 | /** 18 | * When running in Node, we require('./aesprim') and that module takes care of monkey-patching esprima 19 | * using resolve, path finding, etc... 20 | * Anyways, Browserify doesn't support "resolve", so we need to trick the module. We'll actually be 21 | * returning a verbatim, non-modified "esprima" when the code runs require('./aesprim'). 22 | * That is ok because we will modify the "esprima" source code right after the bundle process, via 23 | * the postBundleCB callback. 24 | */ 25 | ["esprima", {expose: "./aesprim"}] 26 | ], 27 | ignore: [ 28 | 'file', 29 | 'system', 30 | 'source-map', 31 | 'estraverse', 32 | 'escodegen', 33 | 'underscore', 34 | 'reflect', 35 | 'JSONSelect', 36 | './lib/aesprim.js' 37 | //'assert' //can't remove because of lib/index.js, 38 | ], 39 | postBundleCB: function(err, src, next) { 40 | /** 41 | * This is ugly, but we need to make "esprima" understand '@' as a valid character. 42 | * It's either this or bundle a copy of the library with those few bytes of changes. 43 | */ 44 | src = src.toString("utf8").replace(/(function isIdentifierStart\(ch\) {\s+return)/m, '$1 (ch == 0x40) || '); 45 | next(err, new Buffer(src, "utf8")); 46 | } 47 | } 48 | } 49 | }, 50 | 51 | uglify: { 52 | options: { 53 | banner: '/*! <%= pkg.name %> <%= pkg.version %> */\n' 54 | }, 55 | build: { 56 | src: '<%= outputFolder %>/<%= pkg.name %>.js', 57 | dest: '<%= outputFolder %>/<%= pkg.name %>.min.js' 58 | } 59 | } 60 | 61 | }); 62 | 63 | grunt.loadNpmTasks('grunt-browserify'); 64 | grunt.loadNpmTasks('grunt-contrib-uglify') 65 | grunt.registerTask('default', ['browserify', 'uglify']); 66 | 67 | }; 68 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2016 David Chester 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/dchester/jsonpath.png?branch=master)](https://travis-ci.org/dchester/jsonpath) 2 | 3 | # jsonpath 4 | 5 | Query JavaScript objects with JSONPath expressions. Robust / safe JSONPath engine for Node.js. 6 | 7 | 8 | ## Query Example 9 | 10 | ```javascript 11 | var cities = [ 12 | { name: "London", "population": 8615246 }, 13 | { name: "Berlin", "population": 3517424 }, 14 | { name: "Madrid", "population": 3165235 }, 15 | { name: "Rome", "population": 2870528 } 16 | ]; 17 | 18 | var jp = require('jsonpath'); 19 | var names = jp.query(cities, '$..name'); 20 | 21 | // [ "London", "Berlin", "Madrid", "Rome" ] 22 | ``` 23 | 24 | ## Install 25 | 26 | Install from npm: 27 | ```bash 28 | $ npm install jsonpath 29 | ``` 30 | 31 | ## JSONPath Syntax 32 | 33 | Here are syntax and examples adapted from [Stefan Goessner's original post](http://goessner.net/articles/JsonPath/) introducing JSONPath in 2007. 34 | 35 | JSONPath | Description 36 | -----------------|------------ 37 | `$` | The root object/element 38 | `@` | The current object/element 39 | `.` | Child member operator 40 | `..` | Recursive descendant operator; JSONPath borrows this syntax from E4X 41 | `*` | Wildcard matching all objects/elements regardless their names 42 | `[]` | Subscript operator 43 | `[,]` | Union operator for alternate names or array indices as a set 44 | `[start:end:step]` | Array slice operator borrowed from ES4 / Python 45 | `?()` | Applies a filter (script) expression via static evaluation 46 | `()` | Script expression via static evaluation 47 | 48 | Given this sample data set, see example expressions below: 49 | 50 | ```javascript 51 | { 52 | "store": { 53 | "book": [ 54 | { 55 | "category": "reference", 56 | "author": "Nigel Rees", 57 | "title": "Sayings of the Century", 58 | "price": 8.95 59 | }, { 60 | "category": "fiction", 61 | "author": "Evelyn Waugh", 62 | "title": "Sword of Honour", 63 | "price": 12.99 64 | }, { 65 | "category": "fiction", 66 | "author": "Herman Melville", 67 | "title": "Moby Dick", 68 | "isbn": "0-553-21311-3", 69 | "price": 8.99 70 | }, { 71 | "category": "fiction", 72 | "author": "J. R. R. Tolkien", 73 | "title": "The Lord of the Rings", 74 | "isbn": "0-395-19395-8", 75 | "price": 22.99 76 | } 77 | ], 78 | "bicycle": { 79 | "color": "red", 80 | "price": 19.95 81 | } 82 | } 83 | } 84 | ``` 85 | 86 | Example JSONPath expressions: 87 | 88 | JSONPath | Description 89 | ------------------------------|------------ 90 | `$.store.book[*].author` | The authors of all books in the store 91 | `$..author` | All authors 92 | `$.store.*` | All things in store, which are some books and a red bicycle 93 | `$.store..price` | The price of everything in the store 94 | `$..book[2]` | The third book 95 | `$..book[(@.length-1)]` | The last book via script subscript 96 | `$..book[-1:]` | The last book via slice 97 | `$..book[0,1]` | The first two books via subscript union 98 | `$..book[:2]` | The first two books via subscript array slice 99 | `$..book[?(@.isbn)]` | Filter all books with isbn number 100 | `$..book[?(@.price<10)]` | Filter all books cheaper than 10 101 | `$..book[?(@.price==8.95)]` | Filter all books that cost 8.95 102 | `$..book[?(@.price<30 && @.category=="fiction")]` | Filter all fiction books cheaper than 30 103 | `$..*` | All members of JSON structure 104 | 105 | 106 | ## Methods 107 | 108 | #### jp.query(obj, pathExpression[, count]) 109 | 110 | Find elements in `obj` matching `pathExpression`. Returns an array of elements that satisfy the provided JSONPath expression, or an empty array if none were matched. Returns only first `count` elements if specified. 111 | 112 | ```javascript 113 | var authors = jp.query(data, '$..author'); 114 | // [ 'Nigel Rees', 'Evelyn Waugh', 'Herman Melville', 'J. R. R. Tolkien' ] 115 | ``` 116 | 117 | #### jp.paths(obj, pathExpression[, count]) 118 | 119 | Find paths to elements in `obj` matching `pathExpression`. Returns an array of element paths that satisfy the provided JSONPath expression. Each path is itself an array of keys representing the location within `obj` of the matching element. Returns only first `count` paths if specified. 120 | 121 | 122 | ```javascript 123 | var paths = jp.paths(data, '$..author'); 124 | // [ 125 | // ['$', 'store', 'book', 0, 'author'] }, 126 | // ['$', 'store', 'book', 1, 'author'] }, 127 | // ['$', 'store', 'book', 2, 'author'] }, 128 | // ['$', 'store', 'book', 3, 'author'] } 129 | // ] 130 | ``` 131 | 132 | #### jp.nodes(obj, pathExpression[, count]) 133 | 134 | Find elements and their corresponding paths in `obj` matching `pathExpression`. Returns an array of node objects where each node has a `path` containing an array of keys representing the location within `obj`, and a `value` pointing to the matched element. Returns only first `count` nodes if specified. 135 | 136 | ```javascript 137 | var nodes = jp.nodes(data, '$..author'); 138 | // [ 139 | // { path: ['$', 'store', 'book', 0, 'author'], value: 'Nigel Rees' }, 140 | // { path: ['$', 'store', 'book', 1, 'author'], value: 'Evelyn Waugh' }, 141 | // { path: ['$', 'store', 'book', 2, 'author'], value: 'Herman Melville' }, 142 | // { path: ['$', 'store', 'book', 3, 'author'], value: 'J. R. R. Tolkien' } 143 | // ] 144 | ``` 145 | 146 | #### jp.value(obj, pathExpression[, newValue]) 147 | 148 | Returns the value of the first element matching `pathExpression`. If `newValue` is provided, sets the value of the first matching element and returns the new value. 149 | 150 | #### jp.parent(obj, pathExpression) 151 | 152 | Returns the parent of the first matching element. 153 | 154 | #### jp.apply(obj, pathExpression, fn) 155 | 156 | Runs the supplied function `fn` on each matching element, and replaces each matching element with the return value from the function. The function accepts the value of the matching element as its only parameter. Returns matching nodes with their updated values. 157 | 158 | 159 | ```javascript 160 | var nodes = jp.apply(data, '$..author', function(value) { return value.toUpperCase() }); 161 | // [ 162 | // { path: ['$', 'store', 'book', 0, 'author'], value: 'NIGEL REES' }, 163 | // { path: ['$', 'store', 'book', 1, 'author'], value: 'EVELYN WAUGH' }, 164 | // { path: ['$', 'store', 'book', 2, 'author'], value: 'HERMAN MELVILLE' }, 165 | // { path: ['$', 'store', 'book', 3, 'author'], value: 'J. R. R. TOLKIEN' } 166 | // ] 167 | ``` 168 | 169 | #### jp.parse(pathExpression) 170 | 171 | Parse the provided JSONPath expression into path components and their associated operations. 172 | 173 | ```javascript 174 | var path = jp.parse('$..author'); 175 | // [ 176 | // { expression: { type: 'root', value: '$' } }, 177 | // { expression: { type: 'identifier', value: 'author' }, operation: 'member', scope: 'descendant' } 178 | // ] 179 | ``` 180 | 181 | #### jp.stringify(path) 182 | 183 | Returns a path expression in string form, given a path. The supplied path may either be a flat array of keys, as returned by `jp.nodes` for example, or may alternatively be a fully parsed path expression in the form of an array of path components as returned by `jp.parse`. 184 | 185 | ```javascript 186 | var pathExpression = jp.stringify(['$', 'store', 'book', 0, 'author']); 187 | // "$.store.book[0].author" 188 | ``` 189 | 190 | ## Differences from Original Implementation 191 | 192 | This implementation aims to be compatible with Stefan Goessner's original implementation with a few notable exceptions described below. 193 | 194 | #### Evaluating Script Expressions 195 | 196 | Script expressions (i.e, `(...)` and `?(...)`) are statically evaluated via [static-eval](https://github.com/substack/static-eval) rather than using the underlying script engine directly. That means both that the scope is limited to the instance variable (`@`), and only simple expressions (with no side effects) will be valid. So for example, `?(@.length>10)` will be just fine to match arrays with more than ten elements, but `?(process.exit())` will not get evaluated since `process` would yield a `ReferenceError`. This method is even safer than `vm.runInNewContext`, since the script engine itself is more limited and entirely distinct from the one running the application code. See more details in the [implementation](https://github.com/substack/static-eval/blob/master/index.js) of the evaluator. 197 | 198 | #### Grammar 199 | 200 | This project uses a formal BNF [grammar](https://github.com/dchester/jsonpath/blob/master/lib/grammar.js) to parse JSONPath expressions, an attempt at reverse-engineering the intent of the original implementation, which parses via a series of creative regular expressions. The original regex approach can sometimes be forgiving for better or for worse (e.g., `$['store]` => `$['store']`), and in other cases, can be just plain wrong (e.g. `[` => `$`). 201 | 202 | #### Other Minor Differences 203 | 204 | As a result of using a real parser and static evaluation, there are some arguable bugs in the original library that have not been carried through here: 205 | 206 | - strings in subscripts may now be double-quoted 207 | - final `step` arguments in slice operators may now be negative 208 | - script expressions may now contain `.` and `@` characters not referring to instance variables 209 | - subscripts no longer act as character slices on string elements 210 | - non-ascii non-word characters are no-longer valid in member identifier names; use quoted subscript strings instead (e.g., `$['$']` instead of `$.$`) 211 | - unions now yield real unions with no duplicates rather than concatenated results 212 | 213 | ## License 214 | 215 | [MIT](LICENSE) 216 | 217 | -------------------------------------------------------------------------------- /bin/generate_parser.js: -------------------------------------------------------------------------------- 1 | var JisonParser = require('jison').Parser; 2 | var grammar = require('../lib/grammar'); 3 | 4 | var parser = new JisonParser(grammar); 5 | source = parser.generate() 6 | 7 | console.log(source) 8 | 9 | -------------------------------------------------------------------------------- /fig.yml: -------------------------------------------------------------------------------- 1 | test: 2 | build: . 3 | command: node /usr/src/app/node_modules/.bin/mocha -u tdd test/ 4 | volumes: 5 | - .:/usr/src/app 6 | -------------------------------------------------------------------------------- /generated/parser.js: -------------------------------------------------------------------------------- 1 | /* parser generated by jison 0.4.13 */ 2 | /* 3 | Returns a Parser object of the following structure: 4 | 5 | Parser: { 6 | yy: {} 7 | } 8 | 9 | Parser.prototype: { 10 | yy: {}, 11 | trace: function(), 12 | symbols_: {associative list: name ==> number}, 13 | terminals_: {associative list: number ==> name}, 14 | productions_: [...], 15 | performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$), 16 | table: [...], 17 | defaultActions: {...}, 18 | parseError: function(str, hash), 19 | parse: function(input), 20 | 21 | lexer: { 22 | EOF: 1, 23 | parseError: function(str, hash), 24 | setInput: function(input), 25 | input: function(), 26 | unput: function(str), 27 | more: function(), 28 | less: function(n), 29 | pastInput: function(), 30 | upcomingInput: function(), 31 | showPosition: function(), 32 | test_match: function(regex_match_array, rule_index), 33 | next: function(), 34 | lex: function(), 35 | begin: function(condition), 36 | popState: function(), 37 | _currentRules: function(), 38 | topState: function(), 39 | pushState: function(condition), 40 | 41 | options: { 42 | ranges: boolean (optional: true ==> token location info will include a .range[] member) 43 | flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match) 44 | backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code) 45 | }, 46 | 47 | performAction: function(yy, yy_, $avoiding_name_collisions, YY_START), 48 | rules: [...], 49 | conditions: {associative list: name ==> set}, 50 | } 51 | } 52 | 53 | 54 | token location info (@$, _$, etc.): { 55 | first_line: n, 56 | last_line: n, 57 | first_column: n, 58 | last_column: n, 59 | range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based) 60 | } 61 | 62 | 63 | the parseError function receives a 'hash' object with these members for lexer and parser errors: { 64 | text: (matched text) 65 | token: (the produced terminal token, if any) 66 | line: (yylineno) 67 | } 68 | while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: { 69 | loc: (yylloc) 70 | expected: (string describing the set of expected tokens) 71 | recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) 72 | } 73 | */ 74 | var parser = (function(){ 75 | var parser = {trace: function trace() { }, 76 | yy: {}, 77 | symbols_: {"error":2,"JSON_PATH":3,"DOLLAR":4,"PATH_COMPONENTS":5,"LEADING_CHILD_MEMBER_EXPRESSION":6,"PATH_COMPONENT":7,"MEMBER_COMPONENT":8,"SUBSCRIPT_COMPONENT":9,"CHILD_MEMBER_COMPONENT":10,"DESCENDANT_MEMBER_COMPONENT":11,"DOT":12,"MEMBER_EXPRESSION":13,"DOT_DOT":14,"STAR":15,"IDENTIFIER":16,"SCRIPT_EXPRESSION":17,"INTEGER":18,"END":19,"CHILD_SUBSCRIPT_COMPONENT":20,"DESCENDANT_SUBSCRIPT_COMPONENT":21,"[":22,"SUBSCRIPT":23,"]":24,"SUBSCRIPT_EXPRESSION":25,"SUBSCRIPT_EXPRESSION_LIST":26,"SUBSCRIPT_EXPRESSION_LISTABLE":27,",":28,"STRING_LITERAL":29,"ARRAY_SLICE":30,"FILTER_EXPRESSION":31,"QQ_STRING":32,"Q_STRING":33,"$accept":0,"$end":1}, 78 | terminals_: {2:"error",4:"DOLLAR",12:"DOT",14:"DOT_DOT",15:"STAR",16:"IDENTIFIER",17:"SCRIPT_EXPRESSION",18:"INTEGER",19:"END",22:"[",24:"]",28:",",30:"ARRAY_SLICE",31:"FILTER_EXPRESSION",32:"QQ_STRING",33:"Q_STRING"}, 79 | productions_: [0,[3,1],[3,2],[3,1],[3,2],[5,1],[5,2],[7,1],[7,1],[8,1],[8,1],[10,2],[6,1],[11,2],[13,1],[13,1],[13,1],[13,1],[13,1],[9,1],[9,1],[20,3],[21,4],[23,1],[23,1],[26,1],[26,3],[27,1],[27,1],[27,1],[25,1],[25,1],[25,1],[29,1],[29,1]], 80 | performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */ 81 | /*``*/) { 82 | /* this == yyval */ 83 | if (!yy.ast) { 84 | yy.ast = _ast; 85 | _ast.initialize(); 86 | } 87 | 88 | var $0 = $$.length - 1; 89 | switch (yystate) { 90 | case 1:yy.ast.set({ expression: { type: "root", value: $$[$0] } }); yy.ast.unshift(); return yy.ast.yield() 91 | break; 92 | case 2:yy.ast.set({ expression: { type: "root", value: $$[$0-1] } }); yy.ast.unshift(); return yy.ast.yield() 93 | break; 94 | case 3:yy.ast.unshift(); return yy.ast.yield() 95 | break; 96 | case 4:yy.ast.set({ operation: "member", scope: "child", expression: { type: "identifier", value: $$[$0-1] }}); yy.ast.unshift(); return yy.ast.yield() 97 | break; 98 | case 5: 99 | break; 100 | case 6: 101 | break; 102 | case 7:yy.ast.set({ operation: "member" }); yy.ast.push() 103 | break; 104 | case 8:yy.ast.set({ operation: "subscript" }); yy.ast.push() 105 | break; 106 | case 9:yy.ast.set({ scope: "child" }) 107 | break; 108 | case 10:yy.ast.set({ scope: "descendant" }) 109 | break; 110 | case 11: 111 | break; 112 | case 12:yy.ast.set({ scope: "child", operation: "member" }) 113 | break; 114 | case 13: 115 | break; 116 | case 14:yy.ast.set({ expression: { type: "wildcard", value: $$[$0] } }) 117 | break; 118 | case 15:yy.ast.set({ expression: { type: "identifier", value: $$[$0] } }) 119 | break; 120 | case 16:yy.ast.set({ expression: { type: "script_expression", value: $$[$0] } }) 121 | break; 122 | case 17:yy.ast.set({ expression: { type: "numeric_literal", value: parseInt($$[$0]) } }) 123 | break; 124 | case 18: 125 | break; 126 | case 19:yy.ast.set({ scope: "child" }) 127 | break; 128 | case 20:yy.ast.set({ scope: "descendant" }) 129 | break; 130 | case 21: 131 | break; 132 | case 22: 133 | break; 134 | case 23: 135 | break; 136 | case 24:$$[$0].length > 1? yy.ast.set({ expression: { type: "union", value: $$[$0] } }) : this.$ = $$[$0] 137 | break; 138 | case 25:this.$ = [$$[$0]] 139 | break; 140 | case 26:this.$ = $$[$0-2].concat($$[$0]) 141 | break; 142 | case 27:this.$ = { expression: { type: "numeric_literal", value: parseInt($$[$0]) } }; yy.ast.set(this.$) 143 | break; 144 | case 28:this.$ = { expression: { type: "string_literal", value: $$[$0] } }; yy.ast.set(this.$) 145 | break; 146 | case 29:this.$ = { expression: { type: "slice", value: $$[$0] } }; yy.ast.set(this.$) 147 | break; 148 | case 30:this.$ = { expression: { type: "wildcard", value: $$[$0] } }; yy.ast.set(this.$) 149 | break; 150 | case 31:this.$ = { expression: { type: "script_expression", value: $$[$0] } }; yy.ast.set(this.$) 151 | break; 152 | case 32:this.$ = { expression: { type: "filter_expression", value: $$[$0] } }; yy.ast.set(this.$) 153 | break; 154 | case 33:this.$ = $$[$0] 155 | break; 156 | case 34:this.$ = $$[$0] 157 | break; 158 | } 159 | }, 160 | table: [{3:1,4:[1,2],6:3,13:4,15:[1,5],16:[1,6],17:[1,7],18:[1,8],19:[1,9]},{1:[3]},{1:[2,1],5:10,7:11,8:12,9:13,10:14,11:15,12:[1,18],14:[1,19],20:16,21:17,22:[1,20]},{1:[2,3],5:21,7:11,8:12,9:13,10:14,11:15,12:[1,18],14:[1,19],20:16,21:17,22:[1,20]},{1:[2,12],12:[2,12],14:[2,12],22:[2,12]},{1:[2,14],12:[2,14],14:[2,14],22:[2,14]},{1:[2,15],12:[2,15],14:[2,15],22:[2,15]},{1:[2,16],12:[2,16],14:[2,16],22:[2,16]},{1:[2,17],12:[2,17],14:[2,17],22:[2,17]},{1:[2,18],12:[2,18],14:[2,18],22:[2,18]},{1:[2,2],7:22,8:12,9:13,10:14,11:15,12:[1,18],14:[1,19],20:16,21:17,22:[1,20]},{1:[2,5],12:[2,5],14:[2,5],22:[2,5]},{1:[2,7],12:[2,7],14:[2,7],22:[2,7]},{1:[2,8],12:[2,8],14:[2,8],22:[2,8]},{1:[2,9],12:[2,9],14:[2,9],22:[2,9]},{1:[2,10],12:[2,10],14:[2,10],22:[2,10]},{1:[2,19],12:[2,19],14:[2,19],22:[2,19]},{1:[2,20],12:[2,20],14:[2,20],22:[2,20]},{13:23,15:[1,5],16:[1,6],17:[1,7],18:[1,8],19:[1,9]},{13:24,15:[1,5],16:[1,6],17:[1,7],18:[1,8],19:[1,9],22:[1,25]},{15:[1,29],17:[1,30],18:[1,33],23:26,25:27,26:28,27:32,29:34,30:[1,35],31:[1,31],32:[1,36],33:[1,37]},{1:[2,4],7:22,8:12,9:13,10:14,11:15,12:[1,18],14:[1,19],20:16,21:17,22:[1,20]},{1:[2,6],12:[2,6],14:[2,6],22:[2,6]},{1:[2,11],12:[2,11],14:[2,11],22:[2,11]},{1:[2,13],12:[2,13],14:[2,13],22:[2,13]},{15:[1,29],17:[1,30],18:[1,33],23:38,25:27,26:28,27:32,29:34,30:[1,35],31:[1,31],32:[1,36],33:[1,37]},{24:[1,39]},{24:[2,23]},{24:[2,24],28:[1,40]},{24:[2,30]},{24:[2,31]},{24:[2,32]},{24:[2,25],28:[2,25]},{24:[2,27],28:[2,27]},{24:[2,28],28:[2,28]},{24:[2,29],28:[2,29]},{24:[2,33],28:[2,33]},{24:[2,34],28:[2,34]},{24:[1,41]},{1:[2,21],12:[2,21],14:[2,21],22:[2,21]},{18:[1,33],27:42,29:34,30:[1,35],32:[1,36],33:[1,37]},{1:[2,22],12:[2,22],14:[2,22],22:[2,22]},{24:[2,26],28:[2,26]}], 161 | defaultActions: {27:[2,23],29:[2,30],30:[2,31],31:[2,32]}, 162 | parseError: function parseError(str, hash) { 163 | if (hash.recoverable) { 164 | this.trace(str); 165 | } else { 166 | throw new Error(str); 167 | } 168 | }, 169 | parse: function parse(input) { 170 | var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; 171 | var args = lstack.slice.call(arguments, 1); 172 | this.lexer.setInput(input); 173 | this.lexer.yy = this.yy; 174 | this.yy.lexer = this.lexer; 175 | this.yy.parser = this; 176 | if (typeof this.lexer.yylloc == 'undefined') { 177 | this.lexer.yylloc = {}; 178 | } 179 | var yyloc = this.lexer.yylloc; 180 | lstack.push(yyloc); 181 | var ranges = this.lexer.options && this.lexer.options.ranges; 182 | if (typeof this.yy.parseError === 'function') { 183 | this.parseError = this.yy.parseError; 184 | } else { 185 | this.parseError = Object.getPrototypeOf(this).parseError; 186 | } 187 | function popStack(n) { 188 | stack.length = stack.length - 2 * n; 189 | vstack.length = vstack.length - n; 190 | lstack.length = lstack.length - n; 191 | } 192 | function lex() { 193 | var token; 194 | token = self.lexer.lex() || EOF; 195 | if (typeof token !== 'number') { 196 | token = self.symbols_[token] || token; 197 | } 198 | return token; 199 | } 200 | var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected; 201 | while (true) { 202 | state = stack[stack.length - 1]; 203 | if (this.defaultActions[state]) { 204 | action = this.defaultActions[state]; 205 | } else { 206 | if (symbol === null || typeof symbol == 'undefined') { 207 | symbol = lex(); 208 | } 209 | action = table[state] && table[state][symbol]; 210 | } 211 | if (typeof action === 'undefined' || !action.length || !action[0]) { 212 | var errStr = ''; 213 | expected = []; 214 | for (p in table[state]) { 215 | if (this.terminals_[p] && p > TERROR) { 216 | expected.push('\'' + this.terminals_[p] + '\''); 217 | } 218 | } 219 | if (this.lexer.showPosition) { 220 | errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + this.lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''; 221 | } else { 222 | errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\''); 223 | } 224 | this.parseError(errStr, { 225 | text: this.lexer.match, 226 | token: this.terminals_[symbol] || symbol, 227 | line: this.lexer.yylineno, 228 | loc: yyloc, 229 | expected: expected 230 | }); 231 | } 232 | if (action[0] instanceof Array && action.length > 1) { 233 | throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol); 234 | } 235 | switch (action[0]) { 236 | case 1: 237 | stack.push(symbol); 238 | vstack.push(this.lexer.yytext); 239 | lstack.push(this.lexer.yylloc); 240 | stack.push(action[1]); 241 | symbol = null; 242 | if (!preErrorSymbol) { 243 | yyleng = this.lexer.yyleng; 244 | yytext = this.lexer.yytext; 245 | yylineno = this.lexer.yylineno; 246 | yyloc = this.lexer.yylloc; 247 | if (recovering > 0) { 248 | recovering--; 249 | } 250 | } else { 251 | symbol = preErrorSymbol; 252 | preErrorSymbol = null; 253 | } 254 | break; 255 | case 2: 256 | len = this.productions_[action[1]][1]; 257 | yyval.$ = vstack[vstack.length - len]; 258 | yyval._$ = { 259 | first_line: lstack[lstack.length - (len || 1)].first_line, 260 | last_line: lstack[lstack.length - 1].last_line, 261 | first_column: lstack[lstack.length - (len || 1)].first_column, 262 | last_column: lstack[lstack.length - 1].last_column 263 | }; 264 | if (ranges) { 265 | yyval._$.range = [ 266 | lstack[lstack.length - (len || 1)].range[0], 267 | lstack[lstack.length - 1].range[1] 268 | ]; 269 | } 270 | r = this.performAction.apply(yyval, [ 271 | yytext, 272 | yyleng, 273 | yylineno, 274 | this.yy, 275 | action[1], 276 | vstack, 277 | lstack 278 | ].concat(args)); 279 | if (typeof r !== 'undefined') { 280 | return r; 281 | } 282 | if (len) { 283 | stack = stack.slice(0, -1 * len * 2); 284 | vstack = vstack.slice(0, -1 * len); 285 | lstack = lstack.slice(0, -1 * len); 286 | } 287 | stack.push(this.productions_[action[1]][0]); 288 | vstack.push(yyval.$); 289 | lstack.push(yyval._$); 290 | newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; 291 | stack.push(newState); 292 | break; 293 | case 3: 294 | return true; 295 | } 296 | } 297 | return true; 298 | }}; 299 | var _ast = { 300 | 301 | initialize: function() { 302 | this._nodes = []; 303 | this._node = {}; 304 | this._stash = []; 305 | }, 306 | 307 | set: function(props) { 308 | for (var k in props) this._node[k] = props[k]; 309 | return this._node; 310 | }, 311 | 312 | node: function(obj) { 313 | if (arguments.length) this._node = obj; 314 | return this._node; 315 | }, 316 | 317 | push: function() { 318 | this._nodes.push(this._node); 319 | this._node = {}; 320 | }, 321 | 322 | unshift: function() { 323 | this._nodes.unshift(this._node); 324 | this._node = {}; 325 | }, 326 | 327 | yield: function() { 328 | var _nodes = this._nodes; 329 | this.initialize(); 330 | return _nodes; 331 | } 332 | }; 333 | /* generated by jison-lex 0.2.1 */ 334 | var lexer = (function(){ 335 | var lexer = { 336 | 337 | EOF:1, 338 | 339 | parseError:function parseError(str, hash) { 340 | if (this.yy.parser) { 341 | this.yy.parser.parseError(str, hash); 342 | } else { 343 | throw new Error(str); 344 | } 345 | }, 346 | 347 | // resets the lexer, sets new input 348 | setInput:function (input) { 349 | this._input = input; 350 | this._more = this._backtrack = this.done = false; 351 | this.yylineno = this.yyleng = 0; 352 | this.yytext = this.matched = this.match = ''; 353 | this.conditionStack = ['INITIAL']; 354 | this.yylloc = { 355 | first_line: 1, 356 | first_column: 0, 357 | last_line: 1, 358 | last_column: 0 359 | }; 360 | if (this.options.ranges) { 361 | this.yylloc.range = [0,0]; 362 | } 363 | this.offset = 0; 364 | return this; 365 | }, 366 | 367 | // consumes and returns one char from the input 368 | input:function () { 369 | var ch = this._input[0]; 370 | this.yytext += ch; 371 | this.yyleng++; 372 | this.offset++; 373 | this.match += ch; 374 | this.matched += ch; 375 | var lines = ch.match(/(?:\r\n?|\n).*/g); 376 | if (lines) { 377 | this.yylineno++; 378 | this.yylloc.last_line++; 379 | } else { 380 | this.yylloc.last_column++; 381 | } 382 | if (this.options.ranges) { 383 | this.yylloc.range[1]++; 384 | } 385 | 386 | this._input = this._input.slice(1); 387 | return ch; 388 | }, 389 | 390 | // unshifts one char (or a string) into the input 391 | unput:function (ch) { 392 | var len = ch.length; 393 | var lines = ch.split(/(?:\r\n?|\n)/g); 394 | 395 | this._input = ch + this._input; 396 | this.yytext = this.yytext.substr(0, this.yytext.length - len - 1); 397 | //this.yyleng -= len; 398 | this.offset -= len; 399 | var oldLines = this.match.split(/(?:\r\n?|\n)/g); 400 | this.match = this.match.substr(0, this.match.length - 1); 401 | this.matched = this.matched.substr(0, this.matched.length - 1); 402 | 403 | if (lines.length - 1) { 404 | this.yylineno -= lines.length - 1; 405 | } 406 | var r = this.yylloc.range; 407 | 408 | this.yylloc = { 409 | first_line: this.yylloc.first_line, 410 | last_line: this.yylineno + 1, 411 | first_column: this.yylloc.first_column, 412 | last_column: lines ? 413 | (lines.length === oldLines.length ? this.yylloc.first_column : 0) 414 | + oldLines[oldLines.length - lines.length].length - lines[0].length : 415 | this.yylloc.first_column - len 416 | }; 417 | 418 | if (this.options.ranges) { 419 | this.yylloc.range = [r[0], r[0] + this.yyleng - len]; 420 | } 421 | this.yyleng = this.yytext.length; 422 | return this; 423 | }, 424 | 425 | // When called from action, caches matched text and appends it on next action 426 | more:function () { 427 | this._more = true; 428 | return this; 429 | }, 430 | 431 | // When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead. 432 | reject:function () { 433 | if (this.options.backtrack_lexer) { 434 | this._backtrack = true; 435 | } else { 436 | return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), { 437 | text: "", 438 | token: null, 439 | line: this.yylineno 440 | }); 441 | 442 | } 443 | return this; 444 | }, 445 | 446 | // retain first n characters of the match 447 | less:function (n) { 448 | this.unput(this.match.slice(n)); 449 | }, 450 | 451 | // displays already matched input, i.e. for error messages 452 | pastInput:function () { 453 | var past = this.matched.substr(0, this.matched.length - this.match.length); 454 | return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); 455 | }, 456 | 457 | // displays upcoming input, i.e. for error messages 458 | upcomingInput:function () { 459 | var next = this.match; 460 | if (next.length < 20) { 461 | next += this._input.substr(0, 20-next.length); 462 | } 463 | return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); 464 | }, 465 | 466 | // displays the character position where the lexing error occurred, i.e. for error messages 467 | showPosition:function () { 468 | var pre = this.pastInput(); 469 | var c = new Array(pre.length + 1).join("-"); 470 | return pre + this.upcomingInput() + "\n" + c + "^"; 471 | }, 472 | 473 | // test the lexed token: return FALSE when not a match, otherwise return token 474 | test_match:function (match, indexed_rule) { 475 | var token, 476 | lines, 477 | backup; 478 | 479 | if (this.options.backtrack_lexer) { 480 | // save context 481 | backup = { 482 | yylineno: this.yylineno, 483 | yylloc: { 484 | first_line: this.yylloc.first_line, 485 | last_line: this.last_line, 486 | first_column: this.yylloc.first_column, 487 | last_column: this.yylloc.last_column 488 | }, 489 | yytext: this.yytext, 490 | match: this.match, 491 | matches: this.matches, 492 | matched: this.matched, 493 | yyleng: this.yyleng, 494 | offset: this.offset, 495 | _more: this._more, 496 | _input: this._input, 497 | yy: this.yy, 498 | conditionStack: this.conditionStack.slice(0), 499 | done: this.done 500 | }; 501 | if (this.options.ranges) { 502 | backup.yylloc.range = this.yylloc.range.slice(0); 503 | } 504 | } 505 | 506 | lines = match[0].match(/(?:\r\n?|\n).*/g); 507 | if (lines) { 508 | this.yylineno += lines.length; 509 | } 510 | this.yylloc = { 511 | first_line: this.yylloc.last_line, 512 | last_line: this.yylineno + 1, 513 | first_column: this.yylloc.last_column, 514 | last_column: lines ? 515 | lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : 516 | this.yylloc.last_column + match[0].length 517 | }; 518 | this.yytext += match[0]; 519 | this.match += match[0]; 520 | this.matches = match; 521 | this.yyleng = this.yytext.length; 522 | if (this.options.ranges) { 523 | this.yylloc.range = [this.offset, this.offset += this.yyleng]; 524 | } 525 | this._more = false; 526 | this._backtrack = false; 527 | this._input = this._input.slice(match[0].length); 528 | this.matched += match[0]; 529 | token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]); 530 | if (this.done && this._input) { 531 | this.done = false; 532 | } 533 | if (token) { 534 | return token; 535 | } else if (this._backtrack) { 536 | // recover context 537 | for (var k in backup) { 538 | this[k] = backup[k]; 539 | } 540 | return false; // rule action called reject() implying the next rule should be tested instead. 541 | } 542 | return false; 543 | }, 544 | 545 | // return next match in input 546 | next:function () { 547 | if (this.done) { 548 | return this.EOF; 549 | } 550 | if (!this._input) { 551 | this.done = true; 552 | } 553 | 554 | var token, 555 | match, 556 | tempMatch, 557 | index; 558 | if (!this._more) { 559 | this.yytext = ''; 560 | this.match = ''; 561 | } 562 | var rules = this._currentRules(); 563 | for (var i = 0; i < rules.length; i++) { 564 | tempMatch = this._input.match(this.rules[rules[i]]); 565 | if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { 566 | match = tempMatch; 567 | index = i; 568 | if (this.options.backtrack_lexer) { 569 | token = this.test_match(tempMatch, rules[i]); 570 | if (token !== false) { 571 | return token; 572 | } else if (this._backtrack) { 573 | match = false; 574 | continue; // rule action called reject() implying a rule MISmatch. 575 | } else { 576 | // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) 577 | return false; 578 | } 579 | } else if (!this.options.flex) { 580 | break; 581 | } 582 | } 583 | } 584 | if (match) { 585 | token = this.test_match(match, rules[index]); 586 | if (token !== false) { 587 | return token; 588 | } 589 | // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) 590 | return false; 591 | } 592 | if (this._input === "") { 593 | return this.EOF; 594 | } else { 595 | return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { 596 | text: "", 597 | token: null, 598 | line: this.yylineno 599 | }); 600 | } 601 | }, 602 | 603 | // return next match that has a token 604 | lex:function lex() { 605 | var r = this.next(); 606 | if (r) { 607 | return r; 608 | } else { 609 | return this.lex(); 610 | } 611 | }, 612 | 613 | // activates a new lexer condition state (pushes the new lexer condition state onto the condition stack) 614 | begin:function begin(condition) { 615 | this.conditionStack.push(condition); 616 | }, 617 | 618 | // pop the previously active lexer condition state off the condition stack 619 | popState:function popState() { 620 | var n = this.conditionStack.length - 1; 621 | if (n > 0) { 622 | return this.conditionStack.pop(); 623 | } else { 624 | return this.conditionStack[0]; 625 | } 626 | }, 627 | 628 | // produce the lexer rule set which is active for the currently active lexer condition state 629 | _currentRules:function _currentRules() { 630 | if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) { 631 | return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; 632 | } else { 633 | return this.conditions["INITIAL"].rules; 634 | } 635 | }, 636 | 637 | // return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available 638 | topState:function topState(n) { 639 | n = this.conditionStack.length - 1 - Math.abs(n || 0); 640 | if (n >= 0) { 641 | return this.conditionStack[n]; 642 | } else { 643 | return "INITIAL"; 644 | } 645 | }, 646 | 647 | // alias for begin(condition) 648 | pushState:function pushState(condition) { 649 | this.begin(condition); 650 | }, 651 | 652 | // return the number of states currently on the stack 653 | stateStackSize:function stateStackSize() { 654 | return this.conditionStack.length; 655 | }, 656 | options: {}, 657 | performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START 658 | /*``*/) { 659 | 660 | var YYSTATE=YY_START; 661 | switch($avoiding_name_collisions) { 662 | case 0:return 4 663 | break; 664 | case 1:return 14 665 | break; 666 | case 2:return 12 667 | break; 668 | case 3:return 15 669 | break; 670 | case 4:return 16 671 | break; 672 | case 5:return 22 673 | break; 674 | case 6:return 24 675 | break; 676 | case 7:return 28 677 | break; 678 | case 8:return 30 679 | break; 680 | case 9:return 18 681 | break; 682 | case 10:yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2); return 32; 683 | break; 684 | case 11:yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2); return 33; 685 | break; 686 | case 12:return 17 687 | break; 688 | case 13:return 31 689 | break; 690 | } 691 | }, 692 | rules: [/^(?:\$)/,/^(?:\.\.)/,/^(?:\.)/,/^(?:\*)/,/^(?:[a-zA-Z_]+[a-zA-Z0-9_]*)/,/^(?:\[)/,/^(?:\])/,/^(?:,)/,/^(?:((-?(?:0|[1-9][0-9]*)))?\:((-?(?:0|[1-9][0-9]*)))?(\:((-?(?:0|[1-9][0-9]*)))?)?)/,/^(?:(-?(?:0|[1-9][0-9]*)))/,/^(?:"(?:\\["bfnrt\/\\]|\\u[a-fA-F0-9]{4}|[^"\\])*")/,/^(?:'(?:\\['bfnrt\/\\]|\\u[a-fA-F0-9]{4}|[^'\\])*')/,/^(?:\(.+?\)(?=\]))/,/^(?:\?\(.+?\)(?=\]))/], 693 | conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13],"inclusive":true}} 694 | }; 695 | return lexer; 696 | })(); 697 | parser.lexer = lexer; 698 | function Parser () { 699 | this.yy = {}; 700 | } 701 | Parser.prototype = parser;parser.Parser = Parser; 702 | return new Parser; 703 | })(); 704 | 705 | 706 | if (typeof require !== 'undefined' && typeof exports !== 'undefined') { 707 | exports.parser = parser; 708 | exports.Parser = parser.Parser; 709 | exports.parse = function () { return parser.parse.apply(parser, arguments); }; 710 | exports.main = function commonjsMain(args) { 711 | if (!args[1]) { 712 | console.log('Usage: '+args[0]+' FILE'); 713 | process.exit(1); 714 | } 715 | var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8"); 716 | return exports.parser.parse(source); 717 | }; 718 | if (typeof module !== 'undefined' && require.main === module) { 719 | exports.main(process.argv.slice(1)); 720 | } 721 | } 722 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/index'); 2 | -------------------------------------------------------------------------------- /jsonpath.min.js: -------------------------------------------------------------------------------- 1 | /*! jsonpath 1.0.0 */ 2 | !function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.jsonpath=a()}}(function(){var a;return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c||a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g=48&&a<=57}function d(a){return"0123456789abcdefABCDEF".indexOf(a)>=0}function e(a){return"01234567".indexOf(a)>=0}function f(a){return 32===a||9===a||11===a||12===a||160===a||a>=5760&&[5760,6158,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8239,8287,12288,65279].indexOf(a)>=0}function g(a){return 10===a||13===a||8232===a||8233===a}function h(a){return 64==a||36===a||95===a||a>=65&&a<=90||a>=97&&a<=122||92===a||a>=128&&eb.NonAsciiIdentifierStart.test(String.fromCharCode(a))}function i(a){return 36===a||95===a||a>=65&&a<=90||a>=97&&a<=122||a>=48&&a<=57||92===a||a>=128&&eb.NonAsciiIdentifierPart.test(String.fromCharCode(a))}function j(a){switch(a){case"class":case"enum":case"export":case"extends":case"import":case"super":return!0;default:return!1}}function k(a){switch(a){case"implements":case"interface":case"package":case"private":case"protected":case"public":case"static":case"yield":case"let":return!0;default:return!1}}function l(a){return"eval"===a||"arguments"===a}function m(a){if(hb&&k(a))return!0;switch(a.length){case 2:return"if"===a||"in"===a||"do"===a;case 3:return"var"===a||"for"===a||"new"===a||"try"===a||"let"===a;case 4:return"this"===a||"else"===a||"case"===a||"void"===a||"with"===a||"enum"===a;case 5:return"while"===a||"break"===a||"catch"===a||"throw"===a||"const"===a||"yield"===a||"class"===a||"super"===a;case 6:return"return"===a||"typeof"===a||"delete"===a||"switch"===a||"export"===a||"import"===a;case 7:return"default"===a||"finally"===a||"extends"===a;case 8:return"function"===a||"continue"===a||"debugger"===a;case 10:return"instanceof"===a;default:return!1}}function n(a,c,d,e,f){var g;b("number"==typeof d,"Comment must have valid position"),ob.lastCommentStart>=d||(ob.lastCommentStart=d,g={type:a,value:c},pb.range&&(g.range=[d,e]),pb.loc&&(g.loc=f),pb.comments.push(g),pb.attachComment&&(pb.leadingComments.push(g),pb.trailingComments.push(g)))}function o(a){var b,c,d,e;for(b=ib-a,c={start:{line:jb,column:ib-kb-a}};ib=lb&&O({},db.UnexpectedToken,"ILLEGAL");else if(42===c){if(47===gb.charCodeAt(ib+1))return++ib,++ib,void(pb.comments&&(d=gb.slice(a+2,ib-2),b.end={line:jb,column:ib-kb},n("Block",d,a,ib,b)));++ib}else++ib;O({},db.UnexpectedToken,"ILLEGAL")}function q(){var a,b;for(b=0===ib;ib>>="===(d=gb.substr(ib,4))?(ib+=4,{type:$a.Punctuator,value:d,lineNumber:jb,lineStart:kb,start:e,end:ib}):">>>"===(c=d.substr(0,3))||"<<="===c||">>="===c?(ib+=3,{type:$a.Punctuator,value:c,lineNumber:jb,lineStart:kb,start:e,end:ib}):(b=c.substr(0,2),g===b[1]&&"+-<>&|".indexOf(g)>=0||"=>"===b?(ib+=2,{type:$a.Punctuator,value:b,lineNumber:jb,lineStart:kb,start:e,end:ib}):"<>=!+-*%&|^/".indexOf(g)>=0?(++ib,{type:$a.Punctuator,value:g,lineNumber:jb,lineStart:kb,start:e,end:ib}):void O({},db.UnexpectedToken,"ILLEGAL"))}function w(a){for(var b="";ib=0&&ib0&&(d=pb.tokens[pb.tokens.length-1],d.range[0]===a&&"Punctuator"===d.type&&("/"!==d.value&&"/="!==d.value||pb.tokens.pop())),pb.tokens.push({type:"RegularExpression",value:c.literal,range:[a,ib],loc:b})),c}function F(a){return a.type===$a.Identifier||a.type===$a.Keyword||a.type===$a.BooleanLiteral||a.type===$a.NullLiteral}function G(){var a,b;if(!(a=pb.tokens[pb.tokens.length-1]))return E();if("Punctuator"===a.type){if("]"===a.value)return v();if(")"===a.value)return b=pb.tokens[pb.openParenToken-1],!b||"Keyword"!==b.type||"if"!==b.value&&"while"!==b.value&&"for"!==b.value&&"with"!==b.value?v():E();if("}"===a.value){if(pb.tokens[pb.openCurlyToken-3]&&"Keyword"===pb.tokens[pb.openCurlyToken-3].type){if(!(b=pb.tokens[pb.openCurlyToken-4]))return v()}else{if(!pb.tokens[pb.openCurlyToken-4]||"Keyword"!==pb.tokens[pb.openCurlyToken-4].type)return v();if(!(b=pb.tokens[pb.openCurlyToken-5]))return E()}return ab.indexOf(b.value)>=0?v():E()}return E()}return"Keyword"===a.type?E():v()}function H(){var a;return q(),ib>=lb?{type:$a.EOF,lineNumber:jb,lineStart:kb,start:ib,end:ib}:(a=gb.charCodeAt(ib),h(a)?u():40===a||41===a||59===a?v():39===a||34===a?z():46===a?c(gb.charCodeAt(ib+1))?y():v():c(a)?y():pb.tokenize&&47===a?G():v())}function I(){var a,b,c;return q(),a={start:{line:jb,column:ib-kb}},b=H(),a.end={line:jb,column:ib-kb},b.type!==$a.EOF&&(c=gb.slice(b.start,b.end),pb.tokens.push({type:_a[b.type],value:c,range:[b.start,b.end],loc:a})),b}function J(){var a;return a=nb,ib=a.end,jb=a.lineNumber,kb=a.lineStart,nb=void 0!==pb.tokens?I():H(),ib=a.end,jb=a.lineNumber,kb=a.lineStart,a}function K(){var a,b,c;a=ib,b=jb,c=kb,nb=void 0!==pb.tokens?I():H(),ib=a,jb=b,kb=c}function L(a,b){this.line=a,this.column=b}function M(a,b,c,d){this.start=new L(a,b),this.end=new L(c,d)}function N(){var a,b,c,d;return a=ib,b=jb,c=kb,q(),d=jb!==b,ib=a,jb=b,kb=c,d}function O(a,c){var d,e=Array.prototype.slice.call(arguments,2),f=c.replace(/%(\d)/g,function(a,c){return b(c>="===a||">>>="===a||"&="===a||"^="===a||"|="===a)}function W(){var a;if(59===gb.charCodeAt(ib)||T(";"))return void J();a=jb,q(),jb===a&&(nb.type===$a.EOF||T("}")||Q(nb))}function X(a){return a.type===bb.Identifier||a.type===bb.MemberExpression}function Y(){var a,b=[];for(a=nb,R("[");!T("]");)T(",")?(J(),b.push(null)):(b.push(pa()),T("]")||R(","));return J(),mb.markEnd(mb.createArrayExpression(b),a)}function Z(a,b){var c,d,e;return c=hb,e=nb,d=Qa(),b&&hb&&l(a[0].name)&&P(b,db.StrictParamName),hb=c,mb.markEnd(mb.createFunctionExpression(null,a,[],d),e)}function $(){var a,b;return b=nb,a=J(),a.type===$a.StringLiteral||a.type===$a.NumericLiteral?(hb&&a.octal&&P(a,db.StrictOctalLiteral),mb.markEnd(mb.createLiteral(a),b)):mb.markEnd(mb.createIdentifier(a.value),b)}function _(){var a,b,c,d,e,f;return a=nb,f=nb,a.type===$a.Identifier?(c=$(),"get"!==a.value||T(":")?"set"!==a.value||T(":")?(R(":"),d=pa(),mb.markEnd(mb.createProperty("init",c,d),f)):(b=$(),R("("),a=nb,a.type!==$a.Identifier?(R(")"),P(a,db.UnexpectedToken,a.value),d=Z([])):(e=[ta()],R(")"),d=Z(e,a)),mb.markEnd(mb.createProperty("set",b,d),f)):(b=$(),R("("),R(")"),d=Z([]),mb.markEnd(mb.createProperty("get",b,d),f))):a.type!==$a.EOF&&a.type!==$a.Punctuator?(b=$(),R(":"),d=pa(),mb.markEnd(mb.createProperty("init",b,d),f)):void Q(a)}function aa(){var a,b,c,d,e,f=[],g={},h=String;for(e=nb,R("{");!T("}");)a=_(),b=a.key.type===bb.Identifier?a.key.name:h(a.key.value),d="init"===a.kind?cb.Data:"get"===a.kind?cb.Get:cb.Set,c="$"+b,Object.prototype.hasOwnProperty.call(g,c)?(g[c]===cb.Data?hb&&d===cb.Data?P({},db.StrictDuplicateProperty):d!==cb.Data&&P({},db.AccessorDataProperty):d===cb.Data?P({},db.AccessorDataProperty):g[c]&d&&P({},db.AccessorGetSet),g[c]|=d):g[c]=d,f.push(a),T("}")||R(",");return R("}"),mb.markEnd(mb.createObjectExpression(f),e)}function ba(){var a;return R("("),a=qa(),R(")"),a}function ca(){var a,b,c,d;if(T("("))return ba();if(T("["))return Y();if(T("{"))return aa();if(a=nb.type,d=nb,a===$a.Identifier)c=mb.createIdentifier(J().value);else if(a===$a.StringLiteral||a===$a.NumericLiteral)hb&&nb.octal&&P(nb,db.StrictOctalLiteral),c=mb.createLiteral(J());else if(a===$a.Keyword){if(U("function"))return Ta();U("this")?(J(),c=mb.createThisExpression()):Q(J())}else a===$a.BooleanLiteral?(b=J(),b.value="true"===b.value,c=mb.createLiteral(b)):a===$a.NullLiteral?(b=J(),b.value=null,c=mb.createLiteral(b)):T("/")||T("/=")?(c=void 0!==pb.tokens?mb.createLiteral(E()):mb.createLiteral(D()),K()):Q(J());return mb.markEnd(c,d)}function da(){var a=[];if(R("("),!T(")"))for(;ib":case"<=":case">=":case"instanceof":c=7;break;case"in":c=b?7:0;break;case"<<":case">>":case">>>":c=8;break;case"+":case"-":c=9;break;case"*":case"/":case"%":c=11}return c}function na(){var a,b,c,d,e,f,g,h,i,j;if(a=nb,i=la(),d=nb,0===(e=ma(d,ob.allowIn)))return i;for(d.prec=e,J(),b=[a,nb],g=la(),f=[i,d,g];(e=ma(nb,ob.allowIn))>0;){for(;f.length>2&&e<=f[f.length-2].prec;)g=f.pop(),h=f.pop().value,i=f.pop(),c=mb.createBinaryExpression(h,i,g),b.pop(),a=b[b.length-1],mb.markEnd(c,a),f.push(c);d=J(),d.prec=e,f.push(d),b.push(nb),c=la(),f.push(c)}for(j=f.length-1,c=f[j],b.pop();j>1;)c=mb.createBinaryExpression(f[j-1].value,f[j-2],c),j-=2,a=b.pop(),mb.markEnd(c,a);return c}function oa(){var a,b,c,d,e;return e=nb,a=na(),T("?")&&(J(),b=ob.allowIn,ob.allowIn=!0,c=pa(),ob.allowIn=b,R(":"),d=pa(),a=mb.createConditionalExpression(a,c,d),mb.markEnd(a,e)),a}function pa(){var a,b,c,d,e;return a=nb,e=nb,d=b=oa(),V()&&(X(b)||P({},db.InvalidLHSInAssignment),hb&&b.type===bb.Identifier&&l(b.name)&&P(a,db.StrictLHSAssignment),a=J(),c=pa(),d=mb.markEnd(mb.createAssignmentExpression(a.value,b,c),e)),d}function qa(){var a,b=nb;if(a=pa(),T(",")){for(a=mb.createSequenceExpression([a]);ib0?1:0,kb=0,lb=gb.length,nb=null,ob={allowIn:!0,labelSet:{},inFunctionBody:!1,inIteration:!1,inSwitch:!1,lastCommentStart:-1},pb={},b=b||{},b.tokens=!0,pb.tokens=[],pb.tokenize=!0,pb.openParenToken=-1,pb.openCurlyToken=-1,pb.range="boolean"==typeof b.range&&b.range,pb.loc="boolean"==typeof b.loc&&b.loc,"boolean"==typeof b.comment&&b.comment&&(pb.comments=[]),"boolean"==typeof b.tolerant&&b.tolerant&&(pb.errors=[]);try{if(K(),nb.type===$a.EOF)return pb.tokens;for(J();nb.type!==$a.EOF;)try{J()}catch(e){if(nb,pb.errors){pb.errors.push(e);break}throw e}Xa(),d=pb.tokens,void 0!==pb.comments&&(d.comments=pb.comments),void 0!==pb.errors&&(d.errors=pb.errors)}catch(f){throw f}finally{pb={}}return d}function Za(a,b){var c,d;d=String,"string"==typeof a||a instanceof String||(a=d(a)),mb=fb,gb=a,ib=0,jb=gb.length>0?1:0,kb=0,lb=gb.length,nb=null,ob={allowIn:!0,labelSet:{},inFunctionBody:!1,inIteration:!1,inSwitch:!1,lastCommentStart:-1},pb={},void 0!==b&&(pb.range="boolean"==typeof b.range&&b.range,pb.loc="boolean"==typeof b.loc&&b.loc,pb.attachComment="boolean"==typeof b.attachComment&&b.attachComment,pb.loc&&null!==b.source&&void 0!==b.source&&(pb.source=d(b.source)),"boolean"==typeof b.tokens&&b.tokens&&(pb.tokens=[]),"boolean"==typeof b.comment&&b.comment&&(pb.comments=[]),"boolean"==typeof b.tolerant&&b.tolerant&&(pb.errors=[]),pb.attachComment&&(pb.range=!0,pb.comments=[],pb.bottomRightStack=[],pb.trailingComments=[],pb.leadingComments=[]));try{c=Wa(),void 0!==pb.comments&&(c.comments=pb.comments),void 0!==pb.tokens&&(Xa(),c.tokens=pb.tokens),void 0!==pb.errors&&(c.errors=pb.errors)}catch(e){throw e}finally{pb={}}return c}var $a,_a,ab,bb,cb,db,eb,fb,gb,hb,ib,jb,kb,lb,mb,nb,ob,pb;$a={BooleanLiteral:1,EOF:2,Identifier:3,Keyword:4,NullLiteral:5,NumericLiteral:6,Punctuator:7,StringLiteral:8,RegularExpression:9},_a={},_a[$a.BooleanLiteral]="Boolean",_a[$a.EOF]="",_a[$a.Identifier]="Identifier",_a[$a.Keyword]="Keyword",_a[$a.NullLiteral]="Null",_a[$a.NumericLiteral]="Numeric",_a[$a.Punctuator]="Punctuator",_a[$a.StringLiteral]="String",_a[$a.RegularExpression]="RegularExpression",ab=["(","{","[","in","typeof","instanceof","new","return","case","delete","throw","void","=","+=","-=","*=","/=","%=","<<=",">>=",">>>=","&=","|=","^=",",","+","-","*","/","%","++","--","<<",">>",">>>","&","|","^","!","~","&&","||","?",":","===","==",">=","<=","<",">","!=","!=="],bb={AssignmentExpression:"AssignmentExpression",ArrayExpression:"ArrayExpression",BlockStatement:"BlockStatement",BinaryExpression:"BinaryExpression",BreakStatement:"BreakStatement",CallExpression:"CallExpression",CatchClause:"CatchClause",ConditionalExpression:"ConditionalExpression",ContinueStatement:"ContinueStatement",DoWhileStatement:"DoWhileStatement",DebuggerStatement:"DebuggerStatement",EmptyStatement:"EmptyStatement",ExpressionStatement:"ExpressionStatement",ForStatement:"ForStatement",ForInStatement:"ForInStatement",FunctionDeclaration:"FunctionDeclaration",FunctionExpression:"FunctionExpression",Identifier:"Identifier",IfStatement:"IfStatement",Literal:"Literal",LabeledStatement:"LabeledStatement",LogicalExpression:"LogicalExpression",MemberExpression:"MemberExpression",NewExpression:"NewExpression",ObjectExpression:"ObjectExpression",Program:"Program",Property:"Property",ReturnStatement:"ReturnStatement",SequenceExpression:"SequenceExpression",SwitchStatement:"SwitchStatement",SwitchCase:"SwitchCase",ThisExpression:"ThisExpression",ThrowStatement:"ThrowStatement",TryStatement:"TryStatement",UnaryExpression:"UnaryExpression",UpdateExpression:"UpdateExpression",VariableDeclaration:"VariableDeclaration",VariableDeclarator:"VariableDeclarator",WhileStatement:"WhileStatement",WithStatement:"WithStatement"},cb={Data:1,Get:2,Set:4},db={UnexpectedToken:"Unexpected token %0",UnexpectedNumber:"Unexpected number",UnexpectedString:"Unexpected string",UnexpectedIdentifier:"Unexpected identifier",UnexpectedReserved:"Unexpected reserved word",UnexpectedEOS:"Unexpected end of input",NewlineAfterThrow:"Illegal newline after throw",InvalidRegExp:"Invalid regular expression",UnterminatedRegExp:"Invalid regular expression: missing /",InvalidLHSInAssignment:"Invalid left-hand side in assignment",InvalidLHSInForIn:"Invalid left-hand side in for-in",MultipleDefaultsInSwitch:"More than one default clause in switch statement",NoCatchOrFinally:"Missing catch or finally after try",UnknownLabel:"Undefined label '%0'",Redeclaration:"%0 '%1' has already been declared",IllegalContinue:"Illegal continue statement",IllegalBreak:"Illegal break statement",IllegalReturn:"Illegal return statement",StrictModeWith:"Strict mode code may not include a with statement",StrictCatchVariable:"Catch variable may not be eval or arguments in strict mode",StrictVarName:"Variable name may not be eval or arguments in strict mode",StrictParamName:"Parameter name eval or arguments is not allowed in strict mode",StrictParamDupe:"Strict mode function may not have duplicate parameter names",StrictFunctionName:"Function name may not be eval or arguments in strict mode",StrictOctalLiteral:"Octal literals are not allowed in strict mode.",StrictDelete:"Delete of an unqualified identifier in strict mode.",StrictDuplicateProperty:"Duplicate data property in object literal not allowed in strict mode", 3 | AccessorDataProperty:"Object literal may not have data and accessor property with the same name",AccessorGetSet:"Object literal may not have multiple get/set accessors with the same name",StrictLHSAssignment:"Assignment to eval or arguments is not allowed in strict mode",StrictLHSPostfix:"Postfix increment/decrement may not have eval or arguments operand in strict mode",StrictLHSPrefix:"Prefix increment/decrement may not have eval or arguments operand in strict mode",StrictReservedWord:"Use of future reserved word in strict mode"},eb={NonAsciiIdentifierStart:new RegExp("[ªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԧԱ-Ֆՙա-ևא-תװ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࢠࢢ-ࢬऄ-हऽॐक़-ॡॱ-ॷॹ-ॿঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-ళవ-హఽౘౙౠౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഅ-ഌഎ-ഐഒ-ഺഽൎൠൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏼᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛮ-ᛰᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤜᥐ-ᥭᥰ-ᥴᦀ-ᦫᧁ-ᧇᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕℙ-ℝℤΩℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎⅠ-ↈⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ々-〇〡-〩〱-〵〸-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿌ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚗꚠ-ꛯꜗ-ꜟꜢ-ꞈꞋ-ꞎꞐ-ꞓꞠ-Ɦꟸ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꪀ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꯀ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ]"),NonAsciiIdentifierPart:new RegExp("[ªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮ̀-ʹͶͷͺ-ͽΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁ҃-҇Ҋ-ԧԱ-Ֆՙա-և֑-ׇֽֿׁׂׅׄא-תװ-ײؐ-ؚؠ-٩ٮ-ۓە-ۜ۟-۪ۨ-ۼۿܐ-݊ݍ-ޱ߀-ߵߺࠀ-࠭ࡀ-࡛ࢠࢢ-ࢬࣤ-ࣾऀ-ॣ०-९ॱ-ॷॹ-ॿঁ-ঃঅ-ঌএঐও-নপ-রলশ-হ়-ৄেৈো-ৎৗড়ঢ়য়-ৣ০-ৱਁ-ਃਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹ਼ਾ-ੂੇੈੋ-੍ੑਖ਼-ੜਫ਼੦-ੵઁ-ઃઅ-ઍએ-ઑઓ-નપ-રલળવ-હ઼-ૅે-ૉો-્ૐૠ-ૣ૦-૯ଁ-ଃଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହ଼-ୄେୈୋ-୍ୖୗଡ଼ଢ଼ୟ-ୣ୦-୯ୱஂஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹா-ூெ-ைொ-்ௐௗ௦-௯ఁ-ఃఅ-ఌఎ-ఐఒ-నప-ళవ-హఽ-ౄె-ైొ-్ౕౖౘౙౠ-ౣ౦-౯ಂಃಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹ಼-ೄೆ-ೈೊ-್ೕೖೞೠ-ೣ೦-೯ೱೲംഃഅ-ഌഎ-ഐഒ-ഺഽ-ൄെ-ൈൊ-ൎൗൠ-ൣ൦-൯ൺ-ൿංඃඅ-ඖක-නඳ-රලව-ෆ්ා-ුූෘ-ෟෲෳก-ฺเ-๎๐-๙ກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ູົ-ຽເ-ໄໆ່-ໍ໐-໙ໜ-ໟༀ༘༙༠-༩༹༵༷༾-ཇཉ-ཬཱ-྄྆-ྗྙ-ྼ࿆က-၉ၐ-ႝႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚ፝-፟ᎀ-ᎏᎠ-Ᏼᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛮ-ᛰᜀ-ᜌᜎ-᜔ᜠ-᜴ᝀ-ᝓᝠ-ᝬᝮ-ᝰᝲᝳក-៓ៗៜ៝០-៩᠋-᠍᠐-᠙ᠠ-ᡷᢀ-ᢪᢰ-ᣵᤀ-ᤜᤠ-ᤫᤰ-᤻᥆-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉ᧐-᧙ᨀ-ᨛᨠ-ᩞ᩠-᩿᩼-᪉᪐-᪙ᪧᬀ-ᭋ᭐-᭙᭫-᭳ᮀ-᯳ᰀ-᰷᱀-᱉ᱍ-ᱽ᳐-᳔᳒-ᳶᴀ-ᷦ᷼-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼ‌‍‿⁀⁔ⁱⁿₐ-ₜ⃐-⃥⃜⃡-⃰ℂℇℊ-ℓℕℙ-ℝℤΩℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎⅠ-ↈⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯ⵿-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⷠ-ⷿⸯ々-〇〡-〯〱-〵〸-〼ぁ-ゖ゙゚ゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿌ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘫꙀ-꙯ꙴ-꙽ꙿ-ꚗꚟ-꛱ꜗ-ꜟꜢ-ꞈꞋ-ꞎꞐ-ꞓꞠ-Ɦꟸ-ꠧꡀ-ꡳꢀ-꣄꣐-꣙꣠-ꣷꣻ꤀-꤭ꤰ-꥓ꥠ-ꥼꦀ-꧀ꧏ-꧙ꨀ-ꨶꩀ-ꩍ꩐-꩙ꩠ-ꩶꩺꩻꪀ-ꫂꫛ-ꫝꫠ-ꫯꫲ-꫶ꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꯀ-ꯪ꯬꯭꯰-꯹가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻ︀-️︠-︦︳︴﹍-﹏ﹰ-ﹴﹶ-ﻼ0-9A-Z_a-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ]")},fb={name:"SyntaxTree",processComment:function(a){var b,c;if(!(a.type===bb.Program&&a.body.length>0)){for(pb.trailingComments.length>0?pb.trailingComments[0].range[0]>=a.range[1]?(c=pb.trailingComments,pb.trailingComments=[]):pb.trailingComments.length=0:pb.bottomRightStack.length>0&&pb.bottomRightStack[pb.bottomRightStack.length-1].trailingComments&&pb.bottomRightStack[pb.bottomRightStack.length-1].trailingComments[0].range[0]>=a.range[1]&&(c=pb.bottomRightStack[pb.bottomRightStack.length-1].trailingComments,delete pb.bottomRightStack[pb.bottomRightStack.length-1].trailingComments);pb.bottomRightStack.length>0&&pb.bottomRightStack[pb.bottomRightStack.length-1].range[0]>=a.range[0];)b=pb.bottomRightStack.pop();b?b.leadingComments&&b.leadingComments[b.leadingComments.length-1].range[1]<=a.range[0]&&(a.leadingComments=b.leadingComments,delete b.leadingComments):pb.leadingComments.length>0&&pb.leadingComments[pb.leadingComments.length-1].range[1]<=a.range[0]&&(a.leadingComments=pb.leadingComments,pb.leadingComments=[]),c&&(a.trailingComments=c),pb.bottomRightStack.push(a)}},markEnd:function(a,b){return pb.range&&(a.range=[b.start,ib]),pb.loc&&(a.loc=new M(void 0===b.startLineNumber?b.lineNumber:b.startLineNumber,b.start-(void 0===b.startLineStart?b.lineStart:b.startLineStart),jb,ib-kb),this.postProcess(a)),pb.attachComment&&this.processComment(a),a},postProcess:function(a){return pb.source&&(a.loc.source=pb.source),a},createArrayExpression:function(a){return{type:bb.ArrayExpression,elements:a}},createAssignmentExpression:function(a,b,c){return{type:bb.AssignmentExpression,operator:a,left:b,right:c}},createBinaryExpression:function(a,b,c){return{type:"||"===a||"&&"===a?bb.LogicalExpression:bb.BinaryExpression,operator:a,left:b,right:c}},createBlockStatement:function(a){return{type:bb.BlockStatement,body:a}},createBreakStatement:function(a){return{type:bb.BreakStatement,label:a}},createCallExpression:function(a,b){return{type:bb.CallExpression,callee:a,arguments:b}},createCatchClause:function(a,b){return{type:bb.CatchClause,param:a,body:b}},createConditionalExpression:function(a,b,c){return{type:bb.ConditionalExpression,test:a,consequent:b,alternate:c}},createContinueStatement:function(a){return{type:bb.ContinueStatement,label:a}},createDebuggerStatement:function(){return{type:bb.DebuggerStatement}},createDoWhileStatement:function(a,b){return{type:bb.DoWhileStatement,body:a,test:b}},createEmptyStatement:function(){return{type:bb.EmptyStatement}},createExpressionStatement:function(a){return{type:bb.ExpressionStatement,expression:a}},createForStatement:function(a,b,c,d){return{type:bb.ForStatement,init:a,test:b,update:c,body:d}},createForInStatement:function(a,b,c){return{type:bb.ForInStatement,left:a,right:b,body:c,each:!1}},createFunctionDeclaration:function(a,b,c,d){return{type:bb.FunctionDeclaration,id:a,params:b,defaults:c,body:d,rest:null,generator:!1,expression:!1}},createFunctionExpression:function(a,b,c,d){return{type:bb.FunctionExpression,id:a,params:b,defaults:c,body:d,rest:null,generator:!1,expression:!1}},createIdentifier:function(a){return{type:bb.Identifier,name:a}},createIfStatement:function(a,b,c){return{type:bb.IfStatement,test:a,consequent:b,alternate:c}},createLabeledStatement:function(a,b){return{type:bb.LabeledStatement,label:a,body:b}},createLiteral:function(a){return{type:bb.Literal,value:a.value,raw:gb.slice(a.start,a.end)}},createMemberExpression:function(a,b,c){return{type:bb.MemberExpression,computed:"["===a,object:b,property:c}},createNewExpression:function(a,b){return{type:bb.NewExpression,callee:a,arguments:b}},createObjectExpression:function(a){return{type:bb.ObjectExpression,properties:a}},createPostfixExpression:function(a,b){return{type:bb.UpdateExpression,operator:a,argument:b,prefix:!1}},createProgram:function(a){return{type:bb.Program,body:a}},createProperty:function(a,b,c){return{type:bb.Property,key:b,value:c,kind:a}},createReturnStatement:function(a){return{type:bb.ReturnStatement,argument:a}},createSequenceExpression:function(a){return{type:bb.SequenceExpression,expressions:a}},createSwitchCase:function(a,b){return{type:bb.SwitchCase,test:a,consequent:b}},createSwitchStatement:function(a,b){return{type:bb.SwitchStatement,discriminant:a,cases:b}},createThisExpression:function(){return{type:bb.ThisExpression}},createThrowStatement:function(a){return{type:bb.ThrowStatement,argument:a}},createTryStatement:function(a,b,c,d){return{type:bb.TryStatement,block:a,guardedHandlers:b,handlers:c,finalizer:d}},createUnaryExpression:function(a,b){return"++"===a||"--"===a?{type:bb.UpdateExpression,operator:a,argument:b,prefix:!0}:{type:bb.UnaryExpression,operator:a,argument:b,prefix:!0}},createVariableDeclaration:function(a,b){return{type:bb.VariableDeclaration,declarations:a,kind:b}},createVariableDeclarator:function(a,b){return{type:bb.VariableDeclarator,id:a,init:b}},createWhileStatement:function(a,b){return{type:bb.WhileStatement,test:a,body:b}},createWithStatement:function(a,b){return{type:bb.WithStatement,object:a,body:b}}},a.version="1.2.2",a.tokenize=Ya,a.parse=Za,a.Syntax=function(){var a,b={};"function"==typeof Object.create&&(b=Object.create(null));for(a in bb)bb.hasOwnProperty(a)&&(b[a]=bb[a]);return"function"==typeof Object.freeze&&Object.freeze(b),b}()})},{}],1:[function(a,b,c){(function(d){var e=function(){function a(){this.yy={}}var b={trace:function(){},yy:{},symbols_:{error:2,JSON_PATH:3,DOLLAR:4,PATH_COMPONENTS:5,LEADING_CHILD_MEMBER_EXPRESSION:6,PATH_COMPONENT:7,MEMBER_COMPONENT:8,SUBSCRIPT_COMPONENT:9,CHILD_MEMBER_COMPONENT:10,DESCENDANT_MEMBER_COMPONENT:11,DOT:12,MEMBER_EXPRESSION:13,DOT_DOT:14,STAR:15,IDENTIFIER:16,SCRIPT_EXPRESSION:17,INTEGER:18,END:19,CHILD_SUBSCRIPT_COMPONENT:20,DESCENDANT_SUBSCRIPT_COMPONENT:21,"[":22,SUBSCRIPT:23,"]":24,SUBSCRIPT_EXPRESSION:25,SUBSCRIPT_EXPRESSION_LIST:26,SUBSCRIPT_EXPRESSION_LISTABLE:27,",":28,STRING_LITERAL:29,ARRAY_SLICE:30,FILTER_EXPRESSION:31,QQ_STRING:32,Q_STRING:33,$accept:0,$end:1},terminals_:{2:"error",4:"DOLLAR",12:"DOT",14:"DOT_DOT",15:"STAR",16:"IDENTIFIER",17:"SCRIPT_EXPRESSION",18:"INTEGER",19:"END",22:"[",24:"]",28:",",30:"ARRAY_SLICE",31:"FILTER_EXPRESSION",32:"QQ_STRING",33:"Q_STRING"},productions_:[0,[3,1],[3,2],[3,1],[3,2],[5,1],[5,2],[7,1],[7,1],[8,1],[8,1],[10,2],[6,1],[11,2],[13,1],[13,1],[13,1],[13,1],[13,1],[9,1],[9,1],[20,3],[21,4],[23,1],[23,1],[26,1],[26,3],[27,1],[27,1],[27,1],[25,1],[25,1],[25,1],[29,1],[29,1]],performAction:function(a,b,d,e,f,g,h){e.ast||(e.ast=c,c.initialize());var i=g.length-1;switch(f){case 1:return e.ast.set({expression:{type:"root",value:g[i]}}),e.ast.unshift(),e.ast.yield();case 2:return e.ast.set({expression:{type:"root",value:g[i-1]}}),e.ast.unshift(),e.ast.yield();case 3:return e.ast.unshift(),e.ast.yield();case 4:return e.ast.set({operation:"member",scope:"child",expression:{type:"identifier",value:g[i-1]}}),e.ast.unshift(),e.ast.yield();case 5:case 6:break;case 7:e.ast.set({operation:"member"}),e.ast.push();break;case 8:e.ast.set({operation:"subscript"}),e.ast.push();break;case 9:e.ast.set({scope:"child"});break;case 10:e.ast.set({scope:"descendant"});break;case 11:break;case 12:e.ast.set({scope:"child",operation:"member"});break;case 13:break;case 14:e.ast.set({expression:{type:"wildcard",value:g[i]}});break;case 15:e.ast.set({expression:{type:"identifier",value:g[i]}});break;case 16:e.ast.set({expression:{type:"script_expression",value:g[i]}});break;case 17:e.ast.set({expression:{type:"numeric_literal",value:parseInt(g[i])}});break;case 18:break;case 19:e.ast.set({scope:"child"});break;case 20:e.ast.set({scope:"descendant"});break;case 21:case 22:case 23:break;case 24:g[i].length>1?e.ast.set({expression:{type:"union",value:g[i]}}):this.$=g[i];break;case 25:this.$=[g[i]];break;case 26:this.$=g[i-2].concat(g[i]);break;case 27:this.$={expression:{type:"numeric_literal",value:parseInt(g[i])}},e.ast.set(this.$);break;case 28:this.$={expression:{type:"string_literal",value:g[i]}},e.ast.set(this.$);break;case 29:this.$={expression:{type:"slice",value:g[i]}},e.ast.set(this.$);break;case 30:this.$={expression:{type:"wildcard",value:g[i]}},e.ast.set(this.$);break;case 31:this.$={expression:{type:"script_expression",value:g[i]}},e.ast.set(this.$);break;case 32:this.$={expression:{type:"filter_expression",value:g[i]}},e.ast.set(this.$);break;case 33:case 34:this.$=g[i]}},table:[{3:1,4:[1,2],6:3,13:4,15:[1,5],16:[1,6],17:[1,7],18:[1,8],19:[1,9]},{1:[3]},{1:[2,1],5:10,7:11,8:12,9:13,10:14,11:15,12:[1,18],14:[1,19],20:16,21:17,22:[1,20]},{1:[2,3],5:21,7:11,8:12,9:13,10:14,11:15,12:[1,18],14:[1,19],20:16,21:17,22:[1,20]},{1:[2,12],12:[2,12],14:[2,12],22:[2,12]},{1:[2,14],12:[2,14],14:[2,14],22:[2,14]},{1:[2,15],12:[2,15],14:[2,15],22:[2,15]},{1:[2,16],12:[2,16],14:[2,16],22:[2,16]},{1:[2,17],12:[2,17],14:[2,17],22:[2,17]},{1:[2,18],12:[2,18],14:[2,18],22:[2,18]},{1:[2,2],7:22,8:12,9:13,10:14,11:15,12:[1,18],14:[1,19],20:16,21:17,22:[1,20]},{1:[2,5],12:[2,5],14:[2,5],22:[2,5]},{1:[2,7],12:[2,7],14:[2,7],22:[2,7]},{1:[2,8],12:[2,8],14:[2,8],22:[2,8]},{1:[2,9],12:[2,9],14:[2,9],22:[2,9]},{1:[2,10],12:[2,10],14:[2,10],22:[2,10]},{1:[2,19],12:[2,19],14:[2,19],22:[2,19]},{1:[2,20],12:[2,20],14:[2,20],22:[2,20]},{13:23,15:[1,5],16:[1,6],17:[1,7],18:[1,8],19:[1,9]},{13:24,15:[1,5],16:[1,6],17:[1,7],18:[1,8],19:[1,9],22:[1,25]},{15:[1,29],17:[1,30],18:[1,33],23:26,25:27,26:28,27:32,29:34,30:[1,35],31:[1,31],32:[1,36],33:[1,37]},{1:[2,4],7:22,8:12,9:13,10:14,11:15,12:[1,18],14:[1,19],20:16,21:17,22:[1,20]},{1:[2,6],12:[2,6],14:[2,6],22:[2,6]},{1:[2,11],12:[2,11],14:[2,11],22:[2,11]},{1:[2,13],12:[2,13],14:[2,13],22:[2,13]},{15:[1,29],17:[1,30],18:[1,33],23:38,25:27,26:28,27:32,29:34,30:[1,35],31:[1,31],32:[1,36],33:[1,37]},{24:[1,39]},{24:[2,23]},{24:[2,24],28:[1,40]},{24:[2,30]},{24:[2,31]},{24:[2,32]},{24:[2,25],28:[2,25]},{24:[2,27],28:[2,27]},{24:[2,28],28:[2,28]},{24:[2,29],28:[2,29]},{24:[2,33],28:[2,33]},{24:[2,34],28:[2,34]},{24:[1,41]},{1:[2,21],12:[2,21],14:[2,21],22:[2,21]},{18:[1,33],27:42,29:34,30:[1,35],32:[1,36],33:[1,37]},{1:[2,22],12:[2,22],14:[2,22],22:[2,22]},{24:[2,26],28:[2,26]}],defaultActions:{27:[2,23],29:[2,30],30:[2,31],31:[2,32]},parseError:function(a,b){if(!b.recoverable)throw new Error(a);this.trace(a)},parse:function(a){function b(){var a;return a=c.lexer.lex()||m,"number"!=typeof a&&(a=c.symbols_[a]||a),a}var c=this,d=[0],e=[null],f=[],g=this.table,h="",i=0,j=0,k=0,l=2,m=1,n=f.slice.call(arguments,1);this.lexer.setInput(a),this.lexer.yy=this.yy,this.yy.lexer=this.lexer,this.yy.parser=this,void 0===this.lexer.yylloc&&(this.lexer.yylloc={});var o=this.lexer.yylloc;f.push(o);var p=this.lexer.options&&this.lexer.options.ranges;"function"==typeof this.yy.parseError?this.parseError=this.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var q,r,s,t,u,v,w,x,y,z={};;){if(s=d[d.length-1],this.defaultActions[s]?t=this.defaultActions[s]:(null!==q&&void 0!==q||(q=b()),t=g[s]&&g[s][q]),void 0===t||!t.length||!t[0]){var A="";y=[];for(v in g[s])this.terminals_[v]&&v>l&&y.push("'"+this.terminals_[v]+"'");A=this.lexer.showPosition?"Parse error on line "+(i+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+y.join(", ")+", got '"+(this.terminals_[q]||q)+"'":"Parse error on line "+(i+1)+": Unexpected "+(q==m?"end of input":"'"+(this.terminals_[q]||q)+"'"),this.parseError(A,{text:this.lexer.match,token:this.terminals_[q]||q,line:this.lexer.yylineno,loc:o,expected:y})}if(t[0]instanceof Array&&t.length>1)throw new Error("Parse Error: multiple actions possible at state: "+s+", token: "+q);switch(t[0]){case 1:d.push(q),e.push(this.lexer.yytext),f.push(this.lexer.yylloc),d.push(t[1]),q=null,r?(q=r,r=null):(j=this.lexer.yyleng,h=this.lexer.yytext,i=this.lexer.yylineno,o=this.lexer.yylloc,k>0&&k--);break;case 2:if(w=this.productions_[t[1]][1],z.$=e[e.length-w],z._$={first_line:f[f.length-(w||1)].first_line,last_line:f[f.length-1].last_line,first_column:f[f.length-(w||1)].first_column,last_column:f[f.length-1].last_column},p&&(z._$.range=[f[f.length-(w||1)].range[0],f[f.length-1].range[1]]),void 0!==(u=this.performAction.apply(z,[h,j,i,this.yy,t[1],e,f].concat(n))))return u;w&&(d=d.slice(0,-1*w*2),e=e.slice(0,-1*w),f=f.slice(0,-1*w)),d.push(this.productions_[t[1]][0]),e.push(z.$),f.push(z._$),x=g[d[d.length-2]][d[d.length-1]],d.push(x);break;case 3:return!0}}return!0}},c={initialize:function(){this._nodes=[],this._node={},this._stash=[]},set:function(a){for(var b in a)this._node[b]=a[b];return this._node},node:function(a){return arguments.length&&(this._node=a),this._node},push:function(){this._nodes.push(this._node),this._node={}},unshift:function(){this._nodes.unshift(this._node),this._node={}},yield:function(){var a=this._nodes;return this.initialize(),a}},d=function(){return{EOF:1,parseError:function(a,b){if(!this.yy.parser)throw new Error(a);this.yy.parser.parseError(a,b)},setInput:function(a){return this._input=a,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var a=this._input[0];return this.yytext+=a,this.yyleng++,this.offset++,this.match+=a,this.matched+=a,a.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),a},unput:function(a){var b=a.length,c=a.split(/(?:\r\n?|\n)/g);this._input=a+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-b-1),this.offset-=b;var d=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),c.length-1&&(this.yylineno-=c.length-1);var e=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:c?(c.length===d.length?this.yylloc.first_column:0)+d[d.length-c.length].length-c[0].length:this.yylloc.first_column-b},this.options.ranges&&(this.yylloc.range=[e[0],e[0]+this.yyleng-b]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(a){this.unput(this.match.slice(a))},pastInput:function(){var a=this.matched.substr(0,this.matched.length-this.match.length);return(a.length>20?"...":"")+a.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var a=this.match;return a.length<20&&(a+=this._input.substr(0,20-a.length)),(a.substr(0,20)+(a.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var a=this.pastInput(),b=new Array(a.length+1).join("-");return a+this.upcomingInput()+"\n"+b+"^"},test_match:function(a,b){var c,d,e;if(this.options.backtrack_lexer&&(e={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(e.yylloc.range=this.yylloc.range.slice(0))),d=a[0].match(/(?:\r\n?|\n).*/g),d&&(this.yylineno+=d.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:d?d[d.length-1].length-d[d.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+a[0].length},this.yytext+=a[0],this.match+=a[0],this.matches=a,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(a[0].length),this.matched+=a[0],c=this.performAction.call(this,this.yy,this,b,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),c)return c;if(this._backtrack){for(var f in e)this[f]=e[f];return!1}return!1},next:function(){if(this.done)return this.EOF;this._input||(this.done=!0);var a,b,c,d;this._more||(this.yytext="",this.match="");for(var e=this._currentRules(),f=0;fb[0].length)){if(b=c,d=f,this.options.backtrack_lexer){if(!1!==(a=this.test_match(c,e[f])))return a;if(this._backtrack){b=!1;continue}return!1}if(!this.options.flex)break}return b?!1!==(a=this.test_match(b,e[d]))&&a:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var a=this.next();return a||this.lex()},begin:function(a){this.conditionStack.push(a)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(a){return a=this.conditionStack.length-1-Math.abs(a||0),a>=0?this.conditionStack[a]:"INITIAL"},pushState:function(a){this.begin(a)},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(a,b,c,d){switch(c){case 0:return 4;case 1:return 14;case 2:return 12;case 3:return 15;case 4:return 16;case 5:return 22;case 6:return 24;case 7:return 28;case 8:return 30;case 9:return 18;case 10:return b.yytext=b.yytext.substr(1,b.yyleng-2),32;case 11:return b.yytext=b.yytext.substr(1,b.yyleng-2),33;case 12:return 17;case 13:return 31}},rules:[/^(?:\$)/,/^(?:\.\.)/,/^(?:\.)/,/^(?:\*)/,/^(?:[a-zA-Z_]+[a-zA-Z0-9_]*)/,/^(?:\[)/,/^(?:\])/,/^(?:,)/,/^(?:((-?(?:0|[1-9][0-9]*)))?\:((-?(?:0|[1-9][0-9]*)))?(\:((-?(?:0|[1-9][0-9]*)))?)?)/,/^(?:(-?(?:0|[1-9][0-9]*)))/,/^(?:"(?:\\["bfnrt\/\\]|\\u[a-fA-F0-9]{4}|[^"\\])*")/,/^(?:'(?:\\['bfnrt\/\\]|\\u[a-fA-F0-9]{4}|[^'\\])*')/,/^(?:\(.+?\)(?=\]))/,/^(?:\?\(.+?\)(?=\]))/],conditions:{INITIAL:{rules:[0,1,2,3,4,5,6,7,8,9,10,11,12,13],inclusive:!0}}}}();return b.lexer=d,a.prototype=b,b.Parser=a,new a}();void 0!==a&&void 0!==c&&(c.parser=e,c.Parser=e.Parser,c.parse=function(){return e.parse.apply(e,arguments)},c.main=function(b){b[1]||(console.log("Usage: "+b[0]+" FILE"),d.exit(1));var e=a("fs").readFileSync(a("path").normalize(b[1]),"utf8");return c.parser.parse(e)},void 0!==b&&a.main===b&&c.main(d.argv.slice(1)))}).call(this,a("_process"))},{_process:14,fs:12,path:13}],2:[function(a,b,c){b.exports={identifier:"[a-zA-Z_]+[a-zA-Z0-9_]*",integer:"-?(?:0|[1-9][0-9]*)",qq_string:'"(?:\\\\["bfnrt/\\\\]|\\\\u[a-fA-F0-9]{4}|[^"\\\\])*"',q_string:"'(?:\\\\['bfnrt/\\\\]|\\\\u[a-fA-F0-9]{4}|[^'\\\\])*'"}},{}],3:[function(a,b,c){var d=a("./dict"),e={lex:{macros:{esc:"\\\\",int:d.integer},rules:[["\\$","return 'DOLLAR'"],["\\.\\.","return 'DOT_DOT'"],["\\.","return 'DOT'"],["\\*","return 'STAR'"],[d.identifier,"return 'IDENTIFIER'"],["\\[","return '['"],["\\]","return ']'"],[",","return ','"],["({int})?\\:({int})?(\\:({int})?)?","return 'ARRAY_SLICE'"],["{int}","return 'INTEGER'"],[d.qq_string,"yytext = yytext.substr(1,yyleng-2); return 'QQ_STRING';"],[d.q_string,"yytext = yytext.substr(1,yyleng-2); return 'Q_STRING';"],["\\(.+?\\)(?=\\])","return 'SCRIPT_EXPRESSION'"],["\\?\\(.+?\\)(?=\\])","return 'FILTER_EXPRESSION'"]]},start:"JSON_PATH",bnf:{JSON_PATH:[["DOLLAR",'yy.ast.set({ expression: { type: "root", value: $1 } }); yy.ast.unshift(); return yy.ast.yield()'],["DOLLAR PATH_COMPONENTS",'yy.ast.set({ expression: { type: "root", value: $1 } }); yy.ast.unshift(); return yy.ast.yield()'],["LEADING_CHILD_MEMBER_EXPRESSION","yy.ast.unshift(); return yy.ast.yield()"],["LEADING_CHILD_MEMBER_EXPRESSION PATH_COMPONENTS",'yy.ast.set({ operation: "member", scope: "child", expression: { type: "identifier", value: $1 }}); yy.ast.unshift(); return yy.ast.yield()']],PATH_COMPONENTS:[["PATH_COMPONENT",""],["PATH_COMPONENTS PATH_COMPONENT",""]],PATH_COMPONENT:[["MEMBER_COMPONENT",'yy.ast.set({ operation: "member" }); yy.ast.push()'],["SUBSCRIPT_COMPONENT",'yy.ast.set({ operation: "subscript" }); yy.ast.push() ']],MEMBER_COMPONENT:[["CHILD_MEMBER_COMPONENT",'yy.ast.set({ scope: "child" })'],["DESCENDANT_MEMBER_COMPONENT",'yy.ast.set({ scope: "descendant" })']],CHILD_MEMBER_COMPONENT:[["DOT MEMBER_EXPRESSION",""]],LEADING_CHILD_MEMBER_EXPRESSION:[["MEMBER_EXPRESSION",'yy.ast.set({ scope: "child", operation: "member" })']],DESCENDANT_MEMBER_COMPONENT:[["DOT_DOT MEMBER_EXPRESSION",""]],MEMBER_EXPRESSION:[["STAR",'yy.ast.set({ expression: { type: "wildcard", value: $1 } })'],["IDENTIFIER",'yy.ast.set({ expression: { type: "identifier", value: $1 } })'],["SCRIPT_EXPRESSION",'yy.ast.set({ expression: { type: "script_expression", value: $1 } })'],["INTEGER",'yy.ast.set({ expression: { type: "numeric_literal", value: parseInt($1) } })'],["END",""]],SUBSCRIPT_COMPONENT:[["CHILD_SUBSCRIPT_COMPONENT",'yy.ast.set({ scope: "child" })'],["DESCENDANT_SUBSCRIPT_COMPONENT",'yy.ast.set({ scope: "descendant" })']],CHILD_SUBSCRIPT_COMPONENT:[["[ SUBSCRIPT ]",""]],DESCENDANT_SUBSCRIPT_COMPONENT:[["DOT_DOT [ SUBSCRIPT ]",""]],SUBSCRIPT:[["SUBSCRIPT_EXPRESSION",""],["SUBSCRIPT_EXPRESSION_LIST",'$1.length > 1? yy.ast.set({ expression: { type: "union", value: $1 } }) : $$ = $1']],SUBSCRIPT_EXPRESSION_LIST:[["SUBSCRIPT_EXPRESSION_LISTABLE","$$ = [$1]"],["SUBSCRIPT_EXPRESSION_LIST , SUBSCRIPT_EXPRESSION_LISTABLE","$$ = $1.concat($3)"]],SUBSCRIPT_EXPRESSION_LISTABLE:[["INTEGER",'$$ = { expression: { type: "numeric_literal", value: parseInt($1) } }; yy.ast.set($$)'],["STRING_LITERAL",'$$ = { expression: { type: "string_literal", value: $1 } }; yy.ast.set($$)'],["ARRAY_SLICE",'$$ = { expression: { type: "slice", value: $1 } }; yy.ast.set($$)']],SUBSCRIPT_EXPRESSION:[["STAR",'$$ = { expression: { type: "wildcard", value: $1 } }; yy.ast.set($$)'],["SCRIPT_EXPRESSION",'$$ = { expression: { type: "script_expression", value: $1 } }; yy.ast.set($$)'],["FILTER_EXPRESSION",'$$ = { expression: { type: "filter_expression", value: $1 } }; yy.ast.set($$)']],STRING_LITERAL:[["QQ_STRING","$$ = $1"],["Q_STRING","$$ = $1"]]}};e.moduleInclude="var _ast = {\n\n initialize: function() {\n this._nodes = [];\n this._node = {};\n this._stash = [];\n },\n\n set: function(props) {\n for (var k in props) this._node[k] = props[k];\n return this._node;\n },\n\n node: function(obj) {\n if (arguments.length) this._node = obj;\n return this._node;\n },\n\n push: function() {\n this._nodes.push(this._node);\n this._node = {};\n },\n\n unshift: function() {\n this._nodes.unshift(this._node);\n this._node = {};\n },\n\n yield: function() {\n var _nodes = this._nodes;\n this.initialize();\n return _nodes;\n }\n};\n",e.actionInclude="if (!yy.ast) {\n yy.ast = _ast;\n _ast.initialize();\n}\n",b.exports=e},{"./dict":2}],4:[function(a,b,c){function d(b,c,d){var e=a("./index"),f=m.parse(c).body[0].expression,g=j(f,{"@":b.value}),h=d.replace(/\{\{\s*value\s*\}\}/g,g),i=e.nodes(b.value,h);return i.forEach(function(a){a.path=b.path.concat(a.path.slice(1))}),i}function e(a){return Array.isArray(a)}function f(a){return a&&!(a instanceof Array)&&a instanceof Object}function g(a){return function(b,c,d,g){var h=b.value,i=b.path,j=[],k=function(b,h){e(b)?(b.forEach(function(a,b){j.length>=g||d(b,a,c)&&j.push({path:h.concat(b),value:a})}),b.forEach(function(b,c){j.length>=g||a&&k(b,h.concat(c))})):f(b)&&(this.keys(b).forEach(function(a){j.length>=g||d(a,b[a],c)&&j.push({path:h.concat(a),value:b[a]})}),this.keys(b).forEach(function(c){j.length>=g||a&&k(b[c],h.concat(c))}))}.bind(this);return k(h,i),j}}function h(a){return function(b,c,d){return this.descend(c,b.expression.value,a,d)}}function i(a){return function(b,c,d){return this.traverse(c,b.expression.value,a,d)}}function j(){try{return o.apply(this,arguments)}catch(a){}}function k(a){return a=a.filter(function(a){return a}),p(a,function(a){return a.path.map(function(a){return String(a).replace("-","--")}).join("-")})}function l(a){var b=String(a);return b.match(/^-?[0-9]+$/)?parseInt(b):null}var m=a("./aesprim"),n=a("./slice"),o=a("static-eval"),p=a("underscore").uniq,q=function(){return this.initialize.apply(this,arguments)};q.prototype.initialize=function(){this.traverse=g(!0),this.descend=g()},q.prototype.keys=Object.keys,q.prototype.resolve=function(a){var b=[a.operation,a.scope,a.expression.type].join("-"),c=this._fns[b];if(!c)throw new Error("couldn't resolve key: "+b);return c.bind(this)},q.prototype.register=function(a,b){if(!b instanceof Function)throw new Error("handler must be a function");this._fns[a]=b},q.prototype._fns={"member-child-identifier":function(a,b){var c=a.expression.value,d=b.value;if(d instanceof Object&&c in d)return[{value:d[c],path:b.path.concat(c)}]},"member-descendant-identifier":i(function(a,b,c){return a==c}),"subscript-child-numeric_literal":h(function(a,b,c){return a===c}),"member-child-numeric_literal":h(function(a,b,c){return String(a)===String(c)}),"subscript-descendant-numeric_literal":i(function(a,b,c){return a===c}),"member-child-wildcard":h(function(){return!0}),"member-descendant-wildcard":i(function(){return!0}),"subscript-descendant-wildcard":i(function(){return!0}),"subscript-child-wildcard":h(function(){return!0}),"subscript-child-slice":function(a,b){if(e(b.value)){var c=a.expression.value.split(":").map(l),d=b.value.map(function(a,c){return{value:a,path:b.path.concat(c)}});return n.apply(null,[d].concat(c))}},"subscript-child-union":function(a,b){var c=[];return a.expression.value.forEach(function(a){var d={operation:"subscript",scope:"child",expression:a.expression},e=this.resolve(d),f=e(d,b);f&&(c=c.concat(f))},this),k(c)},"subscript-descendant-union":function(b,c,d){var e=a(".."),f=this,g=[];return e.nodes(c,"$..*").slice(1).forEach(function(a){g.length>=d||b.expression.value.forEach(function(b){var c={operation:"subscript",scope:"child",expression:b.expression},d=f.resolve(c),e=d(c,a);g=g.concat(e)})}),k(g)},"subscript-child-filter_expression":function(a,b,c){var d=a.expression.value.slice(2,-1),e=m.parse(d).body[0].expression,f=function(a,b){return j(e,{name:function(){return a},"@":b})};return this.descend(b,null,f,c)},"subscript-descendant-filter_expression":function(a,b,c){var d=a.expression.value.slice(2,-1),e=m.parse(d).body[0].expression,f=function(a,b){return j(e,{name:function(){return a},"@":b})};return this.traverse(b,null,f,c)},"subscript-child-script_expression":function(a,b){return d(b,a.expression.value.slice(1,-1),"$[{{value}}]")},"member-child-script_expression":function(a,b){return d(b,a.expression.value.slice(1,-1),"$.{{value}}")},"member-descendant-script_expression":function(a,b){return d(b,a.expression.value.slice(1,-1),"$..value")}},q.prototype._fns["subscript-child-string_literal"]=q.prototype._fns["member-child-identifier"],q.prototype._fns["member-descendant-numeric_literal"]=q.prototype._fns["subscript-descendant-string_literal"]=q.prototype._fns["member-descendant-identifier"],b.exports=q},{"..":"jsonpath","./aesprim":"./aesprim","./index":5,"./slice":7,"static-eval":15,underscore:12}],5:[function(a,b,c){function d(a){return"[object String]"==Object.prototype.toString.call(a)}var e=a("assert"),f=a("./dict"),g=a("./parser"),h=a("./handlers"),i=function(){this.initialize.apply(this,arguments)};i.prototype.initialize=function(){this.parser=new g,this.handlers=new h},i.prototype.parse=function(a){return e.ok(d(a),"we need a path"),this.parser.parse(a)},i.prototype.parent=function(a,b){e.ok(a instanceof Object,"obj needs to be an object"),e.ok(b,"we need a path");var c=this.nodes(a,b)[0];c.path.pop();return this.value(a,c.path)},i.prototype.apply=function(a,b,c){e.ok(a instanceof Object,"obj needs to be an object"),e.ok(b,"we need a path"),e.equal(typeof c,"function","fn needs to be function");var d=this.nodes(a,b).sort(function(a,b){return b.path.length-a.path.length});return d.forEach(function(b){var d=b.path.pop(),e=this.value(a,this.stringify(b.path)),f=b.value=c.call(a,e[d]);e[d]=f},this),d},i.prototype.value=function(a,b,c){if(e.ok(a instanceof Object,"obj needs to be an object"),e.ok(b,"we need a path"),arguments.length>=3){var d=this.nodes(a,b).shift();if(!d)return this._vivify(a,b,c);var f=d.path.slice(-1).shift();this.parent(a,this.stringify(d.path))[f]=c}return this.query(a,this.stringify(b),1).shift()},i.prototype._vivify=function(a,b,c){var d=this;e.ok(a instanceof Object,"obj needs to be an object"),e.ok(b,"we need a path");var f=this.parser.parse(b).map(function(a){return a.expression.value}),g=function(b,c){var e=b.pop(),f=d.value(a,b);f||(g(b.concat(),"string"==typeof e?{}:[]),f=d.value(a,b)),f[e]=c};return g(f,c),this.query(a,b)[0]},i.prototype.query=function(a,b,c){return e.ok(a instanceof Object,"obj needs to be an object"),e.ok(d(b),"we need a path"),this.nodes(a,b,c).map(function(a){return a.value})},i.prototype.paths=function(a,b,c){ 4 | return e.ok(a instanceof Object,"obj needs to be an object"),e.ok(b,"we need a path"),this.nodes(a,b,c).map(function(a){return a.path})},i.prototype.nodes=function(a,b,c){if(e.ok(a instanceof Object,"obj needs to be an object"),e.ok(b,"we need a path"),0===c)return[];var d=this.parser.parse(b),f=this.handlers,g=[{path:["$"],value:a}],h=[];return d.length&&"root"==d[0].expression.type&&d.shift(),d.length?(d.forEach(function(a,b){if(!(h.length>=c)){var e=f.resolve(a),i=[];g.forEach(function(f){if(!(h.length>=c)){var g=e(a,f,c);b==d.length-1?h=h.concat(g||[]):i=i.concat(g||[])}}),g=i}}),c?h.slice(0,c):h):g},i.prototype.stringify=function(a){e.ok(a,"we need a path");var b="$",c={"descendant-member":"..{{value}}","child-member":".{{value}}","descendant-subscript":"..[{{value}}]","child-subscript":"[{{value}}]"};return a=this._normalize(a),a.forEach(function(a){if("root"!=a.expression.type){var d,e=[a.scope,a.operation].join("-"),f=c[e];if(d="string_literal"==a.expression.type?JSON.stringify(a.expression.value):a.expression.value,!f)throw new Error("couldn't find template "+e);b+=f.replace(/{{value}}/,d)}}),b},i.prototype._normalize=function(a){if(e.ok(a,"we need a path"),"string"==typeof a)return this.parser.parse(a);if(Array.isArray(a)&&"string"==typeof a[0]){var b=[{expression:{type:"root",value:"$"}}];return a.forEach(function(a,c){if("$"!=a||0!==c)if("string"==typeof a&&a.match("^"+f.identifier+"$"))b.push({operation:"member",scope:"child",expression:{value:a,type:"identifier"}});else{var d="number"==typeof a?"numeric_literal":"string_literal";b.push({operation:"subscript",scope:"child",expression:{value:a,type:d}})}}),b}if(Array.isArray(a)&&"object"==typeof a[0])return a;throw new Error("couldn't understand path "+a)},i.Handlers=h,i.Parser=g;var j=new i;j.JSONPath=i,b.exports=j},{"./dict":2,"./handlers":4,"./parser":6,assert:8}],6:[function(a,b,c){var d=a("./grammar"),e=a("../generated/parser"),f=function(){var a=new e.Parser,b=a.parseError;return a.yy.parseError=function(){a.yy.ast&&a.yy.ast.initialize(),b.apply(a,arguments)},a};f.grammar=d,b.exports=f},{"../generated/parser":1,"./grammar":3}],7:[function(a,b,c){function d(a){return String(a).match(/^[0-9]+$/)?parseInt(a):Number.isFinite(a)?parseInt(a,10):0}b.exports=function(a,b,c,e){if("string"==typeof b)throw new Error("start cannot be a string");if("string"==typeof c)throw new Error("end cannot be a string");if("string"==typeof e)throw new Error("step cannot be a string");var f=a.length;if(0===e)throw new Error("step cannot be zero");if(e=e?d(e):1,b=b<0?f+b:b,c=c<0?f+c:c,b=d(0===b?0:b||(e>0?0:f-1)),c=d(0===c?0:c||(e>0?f:-1)),b=e>0?Math.max(0,b):Math.min(f,b),c=e>0?Math.min(c,f):Math.max(-1,c),e>0&&c<=b)return[];if(e<0&&b<=c)return[];for(var g=[],h=b;h!=c&&!(e<0&&h<=c||e>0&&h>=c);h+=e)g.push(a[h]);return g}},{}],8:[function(a,b,c){function d(a,b){return n.isUndefined(b)?""+b:n.isNumber(b)&&!isFinite(b)?b.toString():n.isFunction(b)||n.isRegExp(b)?b.toString():b}function e(a,b){return n.isString(a)?a.length=0;f--)if(g[f]!=h[f])return!1;for(f=g.length-1;f>=0;f--)if(e=g[f],!i(a[e],b[e]))return!1;return!0}function l(a,b){return!(!a||!b)&&("[object RegExp]"==Object.prototype.toString.call(b)?b.test(a):a instanceof b||!0===b.call({},a))}function m(a,b,c,d){var e;n.isString(c)&&(d=c,c=null);try{b()}catch(f){e=f}if(d=(c&&c.name?" ("+c.name+").":".")+(d?" "+d:"."),a&&!e&&g(e,c,"Missing expected exception"+d),!a&&l(e,c)&&g(e,c,"Got unwanted exception"+d),a&&e&&c&&!l(e,c)||!a&&e)throw e}var n=a("util/"),o=Array.prototype.slice,p=Object.prototype.hasOwnProperty,q=b.exports=h;q.AssertionError=function(a){this.name="AssertionError",this.actual=a.actual,this.expected=a.expected,this.operator=a.operator,a.message?(this.message=a.message,this.generatedMessage=!1):(this.message=f(this),this.generatedMessage=!0);var b=a.stackStartFunction||g;if(Error.captureStackTrace)Error.captureStackTrace(this,b);else{var c=new Error;if(c.stack){var d=c.stack,e=b.name,h=d.indexOf("\n"+e);if(h>=0){var i=d.indexOf("\n",h+1);d=d.substring(i+1)}this.stack=d}}},n.inherits(q.AssertionError,Error),q.fail=g,q.ok=h,q.equal=function(a,b,c){a!=b&&g(a,b,c,"==",q.equal)},q.notEqual=function(a,b,c){a==b&&g(a,b,c,"!=",q.notEqual)},q.deepEqual=function(a,b,c){i(a,b)||g(a,b,c,"deepEqual",q.deepEqual)},q.notDeepEqual=function(a,b,c){i(a,b)&&g(a,b,c,"notDeepEqual",q.notDeepEqual)},q.strictEqual=function(a,b,c){a!==b&&g(a,b,c,"===",q.strictEqual)},q.notStrictEqual=function(a,b,c){a===b&&g(a,b,c,"!==",q.notStrictEqual)},q.throws=function(a,b,c){m.apply(this,[!0].concat(o.call(arguments)))},q.doesNotThrow=function(a,b){m.apply(this,[!1].concat(o.call(arguments)))},q.ifError=function(a){if(a)throw a};var r=Object.keys||function(a){var b=[];for(var c in a)p.call(a,c)&&b.push(c);return b}},{"util/":11}],9:[function(a,b,c){"function"==typeof Object.create?b.exports=function(a,b){a.super_=b,a.prototype=Object.create(b.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}})}:b.exports=function(a,b){a.super_=b;var c=function(){};c.prototype=b.prototype,a.prototype=new c,a.prototype.constructor=a}},{}],10:[function(a,b,c){b.exports=function(a){return a&&"object"==typeof a&&"function"==typeof a.copy&&"function"==typeof a.fill&&"function"==typeof a.readUInt8}},{}],11:[function(a,b,c){(function(b,d){function e(a,b){var d={seen:[],stylize:g};return arguments.length>=3&&(d.depth=arguments[2]),arguments.length>=4&&(d.colors=arguments[3]),p(b)?d.showHidden=b:b&&c._extend(d,b),v(d.showHidden)&&(d.showHidden=!1),v(d.depth)&&(d.depth=2),v(d.colors)&&(d.colors=!1),v(d.customInspect)&&(d.customInspect=!0),d.colors&&(d.stylize=f),i(d,a,d.depth)}function f(a,b){var c=e.styles[b];return c?"["+e.colors[c][0]+"m"+a+"["+e.colors[c][1]+"m":a}function g(a,b){return a}function h(a){var b={};return a.forEach(function(a,c){b[a]=!0}),b}function i(a,b,d){if(a.customInspect&&b&&A(b.inspect)&&b.inspect!==c.inspect&&(!b.constructor||b.constructor.prototype!==b)){var e=b.inspect(d,a);return t(e)||(e=i(a,e,d)),e}var f=j(a,b);if(f)return f;var g=Object.keys(b),p=h(g);if(a.showHidden&&(g=Object.getOwnPropertyNames(b)),z(b)&&(g.indexOf("message")>=0||g.indexOf("description")>=0))return k(b);if(0===g.length){if(A(b)){var q=b.name?": "+b.name:"";return a.stylize("[Function"+q+"]","special")}if(w(b))return a.stylize(RegExp.prototype.toString.call(b),"regexp");if(y(b))return a.stylize(Date.prototype.toString.call(b),"date");if(z(b))return k(b)}var r="",s=!1,u=["{","}"];if(o(b)&&(s=!0,u=["[","]"]),A(b)){r=" [Function"+(b.name?": "+b.name:"")+"]"}if(w(b)&&(r=" "+RegExp.prototype.toString.call(b)),y(b)&&(r=" "+Date.prototype.toUTCString.call(b)),z(b)&&(r=" "+k(b)),0===g.length&&(!s||0==b.length))return u[0]+r+u[1];if(d<0)return w(b)?a.stylize(RegExp.prototype.toString.call(b),"regexp"):a.stylize("[Object]","special");a.seen.push(b);var v;return v=s?l(a,b,d,p,g):g.map(function(c){return m(a,b,d,p,c,s)}),a.seen.pop(),n(v,r,u)}function j(a,b){if(v(b))return a.stylize("undefined","undefined");if(t(b)){var c="'"+JSON.stringify(b).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return a.stylize(c,"string")}return s(b)?a.stylize(""+b,"number"):p(b)?a.stylize(""+b,"boolean"):q(b)?a.stylize("null","null"):void 0}function k(a){return"["+Error.prototype.toString.call(a)+"]"}function l(a,b,c,d,e){for(var f=[],g=0,h=b.length;g-1&&(h=f?h.split("\n").map(function(a){return" "+a}).join("\n").substr(2):"\n"+h.split("\n").map(function(a){return" "+a}).join("\n"))):h=a.stylize("[Circular]","special")),v(g)){if(f&&e.match(/^\d+$/))return h;g=JSON.stringify(""+e),g.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(g=g.substr(1,g.length-2),g=a.stylize(g,"name")):(g=g.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),g=a.stylize(g,"string"))}return g+": "+h}function n(a,b,c){var d=0;return a.reduce(function(a,b){return d++,b.indexOf("\n")>=0&&d++,a+b.replace(/\u001b\[\d\d?m/g,"").length+1},0)>60?c[0]+(""===b?"":b+"\n ")+" "+a.join(",\n ")+" "+c[1]:c[0]+b+" "+a.join(", ")+" "+c[1]}function o(a){return Array.isArray(a)}function p(a){return"boolean"==typeof a}function q(a){return null===a}function r(a){return null==a}function s(a){return"number"==typeof a}function t(a){return"string"==typeof a}function u(a){return"symbol"==typeof a}function v(a){return void 0===a}function w(a){return x(a)&&"[object RegExp]"===C(a)}function x(a){return"object"==typeof a&&null!==a}function y(a){return x(a)&&"[object Date]"===C(a)}function z(a){return x(a)&&("[object Error]"===C(a)||a instanceof Error)}function A(a){return"function"==typeof a}function B(a){return null===a||"boolean"==typeof a||"number"==typeof a||"string"==typeof a||"symbol"==typeof a||void 0===a}function C(a){return Object.prototype.toString.call(a)}function D(a){return a<10?"0"+a.toString(10):a.toString(10)}function E(){var a=new Date,b=[D(a.getHours()),D(a.getMinutes()),D(a.getSeconds())].join(":");return[a.getDate(),J[a.getMonth()],b].join(" ")}function F(a,b){return Object.prototype.hasOwnProperty.call(a,b)}var G=/%[sdj%]/g;c.format=function(a){if(!t(a)){for(var b=[],c=0;c=f)return a;switch(a){case"%s":return String(d[c++]);case"%d":return Number(d[c++]);case"%j":try{return JSON.stringify(d[c++])}catch(b){return"[Circular]"}default:return a}}),h=d[c];c=0;d--){var e=a[d];"."===e?a.splice(d,1):".."===e?(a.splice(d,1),c++):c&&(a.splice(d,1),c--)}if(b)for(;c--;c)a.unshift("..");return a}function d(a){"string"!=typeof a&&(a+="");var b,c=0,d=-1,e=!0;for(b=a.length-1;b>=0;--b)if(47===a.charCodeAt(b)){if(!e){c=b+1;break}}else-1===d&&(e=!1,d=b+1);return-1===d?"":a.slice(c,d)}function e(a,b){if(a.filter)return a.filter(b);for(var c=[],d=0;d=-1&&!d;f--){var g=f>=0?arguments[f]:a.cwd();if("string"!=typeof g)throw new TypeError("Arguments to path.resolve must be strings");g&&(c=g+"/"+c,d="/"===g.charAt(0))}return c=b(e(c.split("/"),function(a){return!!a}),!d).join("/"),(d?"/":"")+c||"."},c.normalize=function(a){var d=c.isAbsolute(a),g="/"===f(a,-1);return a=b(e(a.split("/"),function(a){return!!a}),!d).join("/"),a||d||(a="."),a&&g&&(a+="/"),(d?"/":"")+a},c.isAbsolute=function(a){return"/"===a.charAt(0)},c.join=function(){var a=Array.prototype.slice.call(arguments,0);return c.normalize(e(a,function(a,b){if("string"!=typeof a)throw new TypeError("Arguments to path.join must be strings");return a}).join("/"))},c.relative=function(a,b){function d(a){for(var b=0;b=0&&""===a[c];c--);return b>c?[]:a.slice(b,c-b+1)}a=c.resolve(a).substr(1),b=c.resolve(b).substr(1);for(var e=d(a.split("/")),f=d(b.split("/")),g=Math.min(e.length,f.length),h=g,i=0;i=1;--f)if(47===(b=a.charCodeAt(f))){if(!e){d=f;break}}else e=!1;return-1===d?c?"/":".":c&&1===d?"/":a.slice(0,d)},c.basename=function(a,b){var c=d(a);return b&&c.substr(-1*b.length)===b&&(c=c.substr(0,c.length-b.length)),c},c.extname=function(a){"string"!=typeof a&&(a+="");for(var b=-1,c=0,d=-1,e=!0,f=0,g=a.length-1;g>=0;--g){var h=a.charCodeAt(g);if(47!==h)-1===d&&(e=!1,d=g+1),46===h?-1===b?b=g:1!==f&&(f=1):-1!==b&&(f=-1);else if(!e){c=g+1;break}}return-1===b||-1===d||0===f||1===f&&b===d-1&&b===c+1?"":a.slice(b,d)};var f="b"==="ab".substr(-1)?function(a,b,c){return a.substr(b,c)}:function(a,b,c){return b<0&&(b=a.length+b),a.substr(b,c)}}).call(this,a("_process"))},{_process:14}],14:[function(a,b,c){function d(){throw new Error("setTimeout has not been defined")}function e(){throw new Error("clearTimeout has not been defined")}function f(a){if(l===setTimeout)return setTimeout(a,0);if((l===d||!l)&&setTimeout)return l=setTimeout,setTimeout(a,0);try{return l(a,0)}catch(b){try{return l.call(null,a,0)}catch(b){return l.call(this,a,0)}}}function g(a){if(m===clearTimeout)return clearTimeout(a);if((m===e||!m)&&clearTimeout)return m=clearTimeout,clearTimeout(a);try{return m(a)}catch(b){try{return m.call(null,a)}catch(b){return m.call(this,a)}}}function h(){q&&o&&(q=!1,o.length?p=o.concat(p):r=-1,p.length&&i())}function i(){if(!q){var a=f(h);q=!0;for(var b=p.length;b;){for(o=p,p=[];++r1)for(var c=1;c"===p?j>o:">="===p?j>=o:"|"===p?j|o:"&"===p?j&o:"^"===p?j^o:"&&"===p?j&&o:"||"===p?j||o:c}if("Identifier"===e.type)return{}.hasOwnProperty.call(b,e.name)?b[e.name]:c;if("ThisExpression"===e.type)return{}.hasOwnProperty.call(b,"this")?b.this:c;if("CallExpression"===e.type){var q=a(e.callee);if(q===c)return c;if("function"!=typeof q)return c;var r=e.callee.object?a(e.callee.object):c;r===c&&(r=null);for(var s=[],i=0,j=e.arguments.length;i 1? yy.ast.set({ expression: { type: "union", value: $1 } }) : $$ = $1' ] ], 80 | 81 | SUBSCRIPT_EXPRESSION_LIST: [ 82 | [ 'SUBSCRIPT_EXPRESSION_LISTABLE', '$$ = [$1]'], 83 | [ 'SUBSCRIPT_EXPRESSION_LIST , SUBSCRIPT_EXPRESSION_LISTABLE', '$$ = $1.concat($3)' ] ], 84 | 85 | SUBSCRIPT_EXPRESSION_LISTABLE: [ 86 | [ 'INTEGER', '$$ = { expression: { type: "numeric_literal", value: parseInt($1) } }; yy.ast.set($$)' ], 87 | [ 'STRING_LITERAL', '$$ = { expression: { type: "string_literal", value: $1 } }; yy.ast.set($$)' ], 88 | [ 'ARRAY_SLICE', '$$ = { expression: { type: "slice", value: $1 } }; yy.ast.set($$)' ] ], 89 | 90 | SUBSCRIPT_EXPRESSION: [ 91 | [ 'STAR', '$$ = { expression: { type: "wildcard", value: $1 } }; yy.ast.set($$)' ], 92 | [ 'SCRIPT_EXPRESSION', '$$ = { expression: { type: "script_expression", value: $1 } }; yy.ast.set($$)' ], 93 | [ 'FILTER_EXPRESSION', '$$ = { expression: { type: "filter_expression", value: $1 } }; yy.ast.set($$)' ] ], 94 | 95 | STRING_LITERAL: [ 96 | [ 'QQ_STRING', "$$ = $1" ], 97 | [ 'Q_STRING', "$$ = $1" ] ] 98 | } 99 | }; 100 | 101 | grammar.moduleInclude = 'var _ast = {\n' + 102 | '\n' + 103 | ' initialize: function() {\n' + 104 | ' this._nodes = [];\n' + 105 | ' this._node = {};\n' + 106 | ' this._stash = [];\n' + 107 | ' },\n' + 108 | '\n' + 109 | ' set: function(props) {\n' + 110 | ' for (var k in props) this._node[k] = props[k];\n' + 111 | ' return this._node;\n' + 112 | ' },\n' + 113 | '\n' + 114 | ' node: function(obj) {\n' + 115 | ' if (arguments.length) this._node = obj;\n' + 116 | ' return this._node;\n' + 117 | ' },\n' + 118 | '\n' + 119 | ' push: function() {\n' + 120 | ' this._nodes.push(this._node);\n' + 121 | ' this._node = {};\n' + 122 | ' },\n' + 123 | '\n' + 124 | ' unshift: function() {\n' + 125 | ' this._nodes.unshift(this._node);\n' + 126 | ' this._node = {};\n' + 127 | ' },\n' + 128 | '\n' + 129 | ' yield: function() {\n' + 130 | ' var _nodes = this._nodes;\n' + 131 | ' this.initialize();\n' + 132 | ' return _nodes;\n' + 133 | ' }\n' + 134 | '};\n'; 135 | grammar.actionInclude = 'if (!yy.ast) {\n' + 136 | ' yy.ast = _ast;\n' + 137 | ' _ast.initialize();\n' + 138 | '}\n'; 139 | 140 | module.exports = grammar; 141 | -------------------------------------------------------------------------------- /lib/handlers.js: -------------------------------------------------------------------------------- 1 | var aesprim = require('./aesprim'); 2 | var slice = require('./slice'); 3 | var _evaluate = require('static-eval'); 4 | var _uniq = require('underscore').uniq; 5 | 6 | var Handlers = function () { 7 | return this.initialize.apply(this, arguments); 8 | } 9 | 10 | Handlers.prototype.initialize = function () { 11 | this.traverse = traverser(true); 12 | this.descend = traverser(); 13 | } 14 | 15 | Handlers.prototype.keys = Object.keys; 16 | 17 | Handlers.prototype.resolve = function (component) { 18 | 19 | var key = [component.operation, component.scope, component.expression.type].join('-'); 20 | var method = this._fns[key]; 21 | 22 | if (!method) throw new Error("couldn't resolve key: " + key); 23 | return method.bind(this); 24 | }; 25 | 26 | Handlers.prototype.register = function (key, handler) { 27 | 28 | if (!handler instanceof Function) { 29 | throw new Error("handler must be a function"); 30 | } 31 | 32 | this._fns[key] = handler; 33 | }; 34 | 35 | Handlers.prototype._fns = { 36 | 37 | 'member-child-identifier': function (component, partial) { 38 | var key = component.expression.value; 39 | var value = partial.value; 40 | if (value instanceof Object && key in value) { 41 | return [{ 42 | value: value[key], 43 | path: partial.path.concat(key) 44 | }] 45 | } 46 | }, 47 | 48 | 'member-descendant-identifier': _traverse(function (key, value, ref) { 49 | return key == ref 50 | }), 51 | 52 | 'subscript-child-numeric_literal': _descend(function (key, value, ref) { 53 | return key === ref 54 | }), 55 | 56 | 'member-child-numeric_literal': _descend(function (key, value, ref) { 57 | return String(key) === String(ref) 58 | }), 59 | 60 | 'subscript-descendant-numeric_literal': _traverse(function (key, value, ref) { 61 | return key === ref 62 | }), 63 | 64 | 'member-child-wildcard': _descend(function () { 65 | return true 66 | }), 67 | 68 | 'member-descendant-wildcard': _traverse(function () { 69 | return true 70 | }), 71 | 72 | 'subscript-descendant-wildcard': _traverse(function () { 73 | return true 74 | }), 75 | 76 | 'subscript-child-wildcard': _descend(function () { 77 | return true 78 | }), 79 | 80 | 'subscript-child-slice': function (component, partial) { 81 | if (is_array(partial.value)) { 82 | var args = component.expression.value.split(':').map(_parse_nullable_int); 83 | var values = partial.value.map(function (v, i) { 84 | return { 85 | value: v, 86 | path: partial.path.concat(i) 87 | } 88 | }); 89 | return slice.apply(null, [values].concat(args)); 90 | } 91 | }, 92 | 93 | 'subscript-child-union': function (component, partial) { 94 | var results = []; 95 | component.expression.value.forEach(function (component) { 96 | var _component = { 97 | operation: 'subscript', 98 | scope: 'child', 99 | expression: component.expression 100 | }; 101 | var handler = this.resolve(_component); 102 | var _results = handler(_component, partial); 103 | if (_results) { 104 | results = results.concat(_results); 105 | } 106 | }, this); 107 | 108 | return unique(results); 109 | }, 110 | 111 | 'subscript-descendant-union': function (component, partial, count) { 112 | 113 | var jp = require('..'); 114 | var self = this; 115 | 116 | var results = []; 117 | var nodes = jp.nodes(partial, '$..*').slice(1); 118 | 119 | nodes.forEach(function (node) { 120 | if (results.length >= count) return; 121 | component.expression.value.forEach(function (component) { 122 | var _component = { 123 | operation: 'subscript', 124 | scope: 'child', 125 | expression: component.expression 126 | }; 127 | var handler = self.resolve(_component); 128 | var _results = handler(_component, node); 129 | results = results.concat(_results); 130 | }); 131 | }); 132 | 133 | return unique(results); 134 | }, 135 | 136 | 'subscript-child-filter_expression': function (component, partial, count) { 137 | 138 | // slice out the expression from ?(expression) 139 | var src = component.expression.value.slice(2, -1); 140 | var ast = aesprim.parse(src).body[0].expression; 141 | 142 | var passable = function (key, value) { 143 | return evaluate(ast, { 144 | name: function () { 145 | return key 146 | }, 147 | '@': value 148 | }); 149 | } 150 | 151 | return this.descend(partial, null, passable, count); 152 | 153 | }, 154 | 155 | 'subscript-descendant-filter_expression': function (component, partial, count) { 156 | 157 | // slice out the expression from ?(expression) 158 | var src = component.expression.value.slice(2, -1); 159 | var ast = aesprim.parse(src).body[0].expression; 160 | 161 | var passable = function (key, value) { 162 | return evaluate(ast, { 163 | name: function () { 164 | return key 165 | }, 166 | '@': value 167 | }); 168 | } 169 | 170 | return this.traverse(partial, null, passable, count); 171 | }, 172 | 173 | 'subscript-child-script_expression': function (component, partial) { 174 | var exp = component.expression.value.slice(1, -1); 175 | return eval_recurse(partial, exp, '$[{{value}}]'); 176 | }, 177 | 178 | 'member-child-script_expression': function (component, partial) { 179 | var exp = component.expression.value.slice(1, -1); 180 | return eval_recurse(partial, exp, '$.{{value}}'); 181 | }, 182 | 183 | 'member-descendant-script_expression': function (component, partial) { 184 | var exp = component.expression.value.slice(1, -1); 185 | return eval_recurse(partial, exp, '$..value'); 186 | } 187 | }; 188 | 189 | Handlers.prototype._fns['subscript-child-string_literal'] = 190 | Handlers.prototype._fns['member-child-identifier']; 191 | 192 | Handlers.prototype._fns['member-descendant-numeric_literal'] = 193 | Handlers.prototype._fns['subscript-descendant-string_literal'] = 194 | Handlers.prototype._fns['member-descendant-identifier']; 195 | 196 | function eval_recurse(partial, src, template) { 197 | 198 | var jp = require('./index'); 199 | var ast = aesprim.parse(src).body[0].expression; 200 | var value = evaluate(ast, { 201 | '@': partial.value 202 | }); 203 | var path = template.replace(/\{\{\s*value\s*\}\}/g, value); 204 | 205 | var results = jp.nodes(partial.value, path); 206 | results.forEach(function (r) { 207 | r.path = partial.path.concat(r.path.slice(1)); 208 | }); 209 | 210 | return results; 211 | } 212 | 213 | function is_array(val) { 214 | return Array.isArray(val); 215 | } 216 | 217 | function is_object(val) { 218 | // is this a non-array, non-null object? 219 | return val && !(val instanceof Array) && val instanceof Object; 220 | } 221 | 222 | function traverser(recurse) { 223 | 224 | return function (partial, ref, passable, count) { 225 | 226 | var value = partial.value; 227 | var path = partial.path; 228 | 229 | var results = []; 230 | 231 | var descend = function (value, path) { 232 | 233 | if (is_array(value)) { 234 | value.forEach(function (element, index) { 235 | if (results.length >= count) { 236 | return 237 | } 238 | if (passable(index, element, ref)) { 239 | results.push({ 240 | path: path.concat(index), 241 | value: element 242 | }); 243 | } 244 | }); 245 | value.forEach(function (element, index) { 246 | if (results.length >= count) { 247 | return 248 | } 249 | if (recurse) { 250 | descend(element, path.concat(index)); 251 | } 252 | }); 253 | } else if (is_object(value)) { 254 | this.keys(value).forEach(function (k) { 255 | if (results.length >= count) { 256 | return 257 | } 258 | if (passable(k, value[k], ref)) { 259 | results.push({ 260 | path: path.concat(k), 261 | value: value[k] 262 | }); 263 | } 264 | }) 265 | this.keys(value).forEach(function (k) { 266 | if (results.length >= count) { 267 | return 268 | } 269 | if (recurse) { 270 | descend(value[k], path.concat(k)); 271 | } 272 | }); 273 | } 274 | }.bind(this); 275 | descend(value, path); 276 | return results; 277 | } 278 | } 279 | 280 | function _descend(passable) { 281 | return function (component, partial, count) { 282 | return this.descend(partial, component.expression.value, passable, count); 283 | } 284 | } 285 | 286 | function _traverse(passable) { 287 | return function (component, partial, count) { 288 | return this.traverse(partial, component.expression.value, passable, count); 289 | } 290 | } 291 | 292 | function evaluate() { 293 | try { 294 | return _evaluate.apply(this, arguments) 295 | } catch (e) {} 296 | } 297 | 298 | function unique(results) { 299 | results = results.filter(function (d) { 300 | return d 301 | }) 302 | return _uniq( 303 | results, 304 | function (r) { 305 | return r.path.map(function (c) { 306 | return String(c).replace('-', '--') 307 | }).join('-') 308 | } 309 | ); 310 | } 311 | 312 | function _parse_nullable_int(val) { 313 | var sval = String(val); 314 | return sval.match(/^-?[0-9]+$/) ? parseInt(sval) : null; 315 | } 316 | 317 | module.exports = Handlers; -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var dict = require('./dict'); 3 | var Parser = require('./parser'); 4 | var Handlers = require('./handlers'); 5 | 6 | var JSONPath = function() { 7 | this.initialize.apply(this, arguments); 8 | }; 9 | 10 | JSONPath.prototype.initialize = function() { 11 | this.parser = new Parser(); 12 | this.handlers = new Handlers(); 13 | }; 14 | 15 | JSONPath.prototype.parse = function(string) { 16 | assert.ok(_is_string(string), "we need a path"); 17 | return this.parser.parse(string); 18 | }; 19 | 20 | JSONPath.prototype.parent = function(obj, string) { 21 | 22 | assert.ok(obj instanceof Object, "obj needs to be an object"); 23 | assert.ok(string, "we need a path"); 24 | 25 | var node = this.nodes(obj, string)[0]; 26 | var key = node.path.pop(); /* jshint unused:false */ 27 | return this.value(obj, node.path); 28 | } 29 | 30 | JSONPath.prototype.apply = function(obj, string, fn) { 31 | 32 | assert.ok(obj instanceof Object, "obj needs to be an object"); 33 | assert.ok(string, "we need a path"); 34 | assert.equal(typeof fn, "function", "fn needs to be function") 35 | 36 | var nodes = this.nodes(obj, string).sort(function(a, b) { 37 | // sort nodes so we apply from the bottom up 38 | return b.path.length - a.path.length; 39 | }); 40 | 41 | nodes.forEach(function(node) { 42 | var key = node.path.pop(); 43 | var parent = this.value(obj, this.stringify(node.path)); 44 | var val = node.value = fn.call(obj, parent[key]); 45 | parent[key] = val; 46 | }, this); 47 | 48 | return nodes; 49 | } 50 | 51 | JSONPath.prototype.value = function(obj, path, value) { 52 | 53 | assert.ok(obj instanceof Object, "obj needs to be an object"); 54 | assert.ok(path, "we need a path"); 55 | 56 | if (arguments.length >= 3) { 57 | var node = this.nodes(obj, path).shift(); 58 | if (!node) return this._vivify(obj, path, value); 59 | var key = node.path.slice(-1).shift(); 60 | var parent = this.parent(obj, this.stringify(node.path)); 61 | parent[key] = value; 62 | } 63 | return this.query(obj, this.stringify(path), 1).shift(); 64 | } 65 | 66 | JSONPath.prototype._vivify = function(obj, string, value) { 67 | 68 | var self = this; 69 | 70 | assert.ok(obj instanceof Object, "obj needs to be an object"); 71 | assert.ok(string, "we need a path"); 72 | 73 | var path = this.parser.parse(string) 74 | .map(function(component) { return component.expression.value }); 75 | 76 | var setValue = function(path, value) { 77 | var key = path.pop(); 78 | var node = self.value(obj, path); 79 | if (!node) { 80 | setValue(path.concat(), typeof key === 'string' ? {} : []); 81 | node = self.value(obj, path); 82 | } 83 | node[key] = value; 84 | } 85 | setValue(path, value); 86 | return this.query(obj, string)[0]; 87 | } 88 | 89 | JSONPath.prototype.query = function(obj, string, count) { 90 | 91 | assert.ok(obj instanceof Object, "obj needs to be an object"); 92 | assert.ok(_is_string(string), "we need a path"); 93 | 94 | var results = this.nodes(obj, string, count) 95 | .map(function(r) { return r.value }); 96 | 97 | return results; 98 | }; 99 | 100 | JSONPath.prototype.paths = function(obj, string, count) { 101 | 102 | assert.ok(obj instanceof Object, "obj needs to be an object"); 103 | assert.ok(string, "we need a path"); 104 | 105 | var results = this.nodes(obj, string, count) 106 | .map(function(r) { return r.path }); 107 | 108 | return results; 109 | }; 110 | 111 | JSONPath.prototype.nodes = function(obj, string, count) { 112 | 113 | assert.ok(obj instanceof Object, "obj needs to be an object"); 114 | assert.ok(string, "we need a path"); 115 | 116 | if (count === 0) return []; 117 | 118 | var path = this.parser.parse(string); 119 | var handlers = this.handlers; 120 | 121 | var partials = [ { path: ['$'], value: obj } ]; 122 | var matches = []; 123 | 124 | if (path.length && path[0].expression.type == 'root') path.shift(); 125 | 126 | if (!path.length) return partials; 127 | 128 | path.forEach(function(component, index) { 129 | 130 | if (matches.length >= count) return; 131 | var handler = handlers.resolve(component); 132 | var _partials = []; 133 | 134 | partials.forEach(function(p) { 135 | 136 | if (matches.length >= count) return; 137 | var results = handler(component, p, count); 138 | 139 | if (index == path.length - 1) { 140 | // if we're through the components we're done 141 | matches = matches.concat(results || []); 142 | } else { 143 | // otherwise accumulate and carry on through 144 | _partials = _partials.concat(results || []); 145 | } 146 | }); 147 | 148 | partials = _partials; 149 | 150 | }); 151 | 152 | return count ? matches.slice(0, count) : matches; 153 | }; 154 | 155 | JSONPath.prototype.stringify = function(path) { 156 | 157 | assert.ok(path, "we need a path"); 158 | 159 | var string = '$'; 160 | 161 | var templates = { 162 | 'descendant-member': '..{{value}}', 163 | 'child-member': '.{{value}}', 164 | 'descendant-subscript': '..[{{value}}]', 165 | 'child-subscript': '[{{value}}]' 166 | }; 167 | 168 | path = this._normalize(path); 169 | 170 | path.forEach(function(component) { 171 | 172 | if (component.expression.type == 'root') return; 173 | 174 | var key = [component.scope, component.operation].join('-'); 175 | var template = templates[key]; 176 | var value; 177 | 178 | if (component.expression.type == 'string_literal') { 179 | value = JSON.stringify(component.expression.value) 180 | } else { 181 | value = component.expression.value; 182 | } 183 | 184 | if (!template) throw new Error("couldn't find template " + key); 185 | 186 | string += template.replace(/{{value}}/, value); 187 | }); 188 | 189 | return string; 190 | } 191 | 192 | JSONPath.prototype._normalize = function(path) { 193 | 194 | assert.ok(path, "we need a path"); 195 | 196 | if (typeof path == "string") { 197 | 198 | return this.parser.parse(path); 199 | 200 | } else if (Array.isArray(path) && typeof path[0] == "string") { 201 | 202 | var _path = [ { expression: { type: "root", value: "$" } } ]; 203 | 204 | path.forEach(function(component, index) { 205 | 206 | if (component == '$' && index === 0) return; 207 | 208 | if (typeof component == "string" && component.match("^" + dict.identifier + "$")) { 209 | 210 | _path.push({ 211 | operation: 'member', 212 | scope: 'child', 213 | expression: { value: component, type: 'identifier' } 214 | }); 215 | 216 | } else { 217 | 218 | var type = typeof component == "number" ? 219 | 'numeric_literal' : 'string_literal'; 220 | 221 | _path.push({ 222 | operation: 'subscript', 223 | scope: 'child', 224 | expression: { value: component, type: type } 225 | }); 226 | } 227 | }); 228 | 229 | return _path; 230 | 231 | } else if (Array.isArray(path) && typeof path[0] == "object") { 232 | 233 | return path 234 | } 235 | 236 | throw new Error("couldn't understand path " + path); 237 | } 238 | 239 | function _is_string(obj) { 240 | return Object.prototype.toString.call(obj) == '[object String]'; 241 | } 242 | 243 | JSONPath.Handlers = Handlers; 244 | JSONPath.Parser = Parser; 245 | 246 | var instance = new JSONPath; 247 | instance.JSONPath = JSONPath; 248 | 249 | module.exports = instance; 250 | -------------------------------------------------------------------------------- /lib/parser.js: -------------------------------------------------------------------------------- 1 | var grammar = require('./grammar'); 2 | var gparser = require('../generated/parser'); 3 | 4 | var Parser = function() { 5 | 6 | var parser = new gparser.Parser(); 7 | 8 | var _parseError = parser.parseError; 9 | parser.yy.parseError = function() { 10 | if (parser.yy.ast) { 11 | parser.yy.ast.initialize(); 12 | } 13 | _parseError.apply(parser, arguments); 14 | } 15 | 16 | return parser; 17 | 18 | }; 19 | 20 | Parser.grammar = grammar; 21 | module.exports = Parser; 22 | -------------------------------------------------------------------------------- /lib/slice.js: -------------------------------------------------------------------------------- 1 | module.exports = function(arr, start, end, step) { 2 | 3 | if (typeof start == 'string') throw new Error("start cannot be a string"); 4 | if (typeof end == 'string') throw new Error("end cannot be a string"); 5 | if (typeof step == 'string') throw new Error("step cannot be a string"); 6 | 7 | var len = arr.length; 8 | 9 | if (step === 0) throw new Error("step cannot be zero"); 10 | step = step ? integer(step) : 1; 11 | 12 | // normalize negative values 13 | start = start < 0 ? len + start : start; 14 | end = end < 0 ? len + end : end; 15 | 16 | // default extents to extents 17 | start = integer(start === 0 ? 0 : !start ? (step > 0 ? 0 : len - 1) : start); 18 | end = integer(end === 0 ? 0 : !end ? (step > 0 ? len : -1) : end); 19 | 20 | // clamp extents 21 | start = step > 0 ? Math.max(0, start) : Math.min(len, start); 22 | end = step > 0 ? Math.min(end, len) : Math.max(-1, end); 23 | 24 | // return empty if extents are backwards 25 | if (step > 0 && end <= start) return []; 26 | if (step < 0 && start <= end) return []; 27 | 28 | var result = []; 29 | 30 | for (var i = start; i != end; i += step) { 31 | if ((step < 0 && i <= end) || (step > 0 && i >= end)) break; 32 | result.push(arr[i]); 33 | } 34 | 35 | return result; 36 | } 37 | 38 | function integer(val) { 39 | return String(val).match(/^[0-9]+$/) ? parseInt(val) : 40 | Number.isFinite(val) ? parseInt(val, 10) : 0; 41 | } 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsonpath", 3 | "description": "Query JavaScript objects with JSONPath expressions. Robust / safe JSONPath engine for Node.js.", 4 | "version": "1.0.0", 5 | "author": "david@fmail.co.uk", 6 | "scripts": { 7 | "test": "mocha -u tdd test && jscs lib && jshint lib", 8 | "generate": "node bin/generate_parser.js > generated/parser.js" 9 | }, 10 | "dependencies": { 11 | "esprima": "1.2.2", 12 | "jison": "0.4.13", 13 | "static-eval": "2.0.0", 14 | "underscore": "1.7.0" 15 | }, 16 | "browser": { 17 | "./lib/aesprim.js": "./generated/aesprim-browser.js" 18 | }, 19 | "devDependencies": { 20 | "grunt": "0.4.5", 21 | "grunt-browserify": "3.8.0", 22 | "grunt-cli": "0.1.13", 23 | "grunt-contrib-uglify": "0.9.1", 24 | "jscs": "1.10.0", 25 | "jshint": "2.6.0", 26 | "mocha": "2.1.0" 27 | }, 28 | "repository": { 29 | "type": "git", 30 | "url": "https://github.com/dchester/jsonpath" 31 | }, 32 | "keywords": [ 33 | "JSONPath", 34 | "jsonpath", 35 | "json-path", 36 | "object", 37 | "traversal", 38 | "json", 39 | "path", 40 | "data structures" 41 | ], 42 | "license": "MIT" 43 | } 44 | -------------------------------------------------------------------------------- /test/data/store.json: -------------------------------------------------------------------------------- 1 | { "store": { 2 | "book": [ 3 | { "category": "reference", 4 | "author": "Nigel Rees", 5 | "title": "Sayings of the Century", 6 | "price": 8.95 7 | }, 8 | { "category": "fiction", 9 | "author": "Evelyn Waugh", 10 | "title": "Sword of Honour", 11 | "price": 12.99 12 | }, 13 | { "category": "fiction", 14 | "author": "Herman Melville", 15 | "title": "Moby Dick", 16 | "isbn": "0-553-21311-3", 17 | "price": 8.99 18 | }, 19 | { "category": "fiction", 20 | "author": "J. R. R. Tolkien", 21 | "title": "The Lord of the Rings", 22 | "isbn": "0-395-19395-8", 23 | "price": 22.99 24 | } 25 | ], 26 | "bicycle": { 27 | "color": "red", 28 | "price": 19.95 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/lessons.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var jp = require('../'); 3 | 4 | var data = require('./data/store.json'); 5 | 6 | suite('orig-google-code-issues', function() { 7 | 8 | test('comma in eval', function() { 9 | var pathExpression = '$..book[?(@.price && ",")]' 10 | var results = jp.query(data, pathExpression); 11 | assert.deepEqual(results, data.store.book); 12 | }); 13 | 14 | test('member names with dots', function() { 15 | var data = { 'www.google.com': 42, 'www.wikipedia.org': 190 }; 16 | var results = jp.query(data, "$['www.google.com']"); 17 | assert.deepEqual(results, [ 42 ]); 18 | }); 19 | 20 | test('nested objects with filter', function() { 21 | var data = { dataResult: { object: { objectInfo: { className: "folder", typeName: "Standard Folder", id: "uniqueId" } } } }; 22 | var results = jp.query(data, "$..object[?(@.className=='folder')]"); 23 | assert.deepEqual(results, [ data.dataResult.object.objectInfo ]); 24 | }); 25 | 26 | test('script expressions with @ char', function() { 27 | var data = { "DIV": [{ "@class": "value", "val": 5 }] }; 28 | var results = jp.query(data, "$..DIV[?(@['@class']=='value')]"); 29 | assert.deepEqual(results, data.DIV); 30 | }); 31 | 32 | test('negative slices', function() { 33 | var results = jp.query(data, "$..book[-1:].title"); 34 | assert.deepEqual(results, ['The Lord of the Rings']); 35 | }); 36 | 37 | }); 38 | 39 | -------------------------------------------------------------------------------- /test/parse.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var jp = require('../'); 3 | var util = require('util'); 4 | 5 | suite('parse', function() { 6 | 7 | test('should parse root-only', function() { 8 | var path = jp.parse('$'); 9 | assert.deepEqual(path, [ { expression: { type: 'root', value: '$' } } ]); 10 | }); 11 | 12 | test('parse path for store', function() { 13 | var path = jp.parse('$.store'); 14 | assert.deepEqual(path, [ 15 | { expression: { type: 'root', value: '$' } }, 16 | { operation: 'member', scope: 'child', expression: { type: 'identifier', value: 'store' } } 17 | ]) 18 | }); 19 | 20 | test('parse path for the authors of all books in the store', function() { 21 | var path = jp.parse('$.store.book[*].author'); 22 | assert.deepEqual(path, [ 23 | { expression: { type: 'root', value: '$' } }, 24 | { operation: 'member', scope: 'child', expression: { type: 'identifier', value: 'store' } }, 25 | { operation: 'member', scope: 'child', expression: { type: 'identifier', value: 'book' } }, 26 | { operation: 'subscript', scope: 'child', expression: { type: 'wildcard', value: '*' } }, 27 | { operation: 'member', scope: 'child', expression: { type: 'identifier', value: 'author' } } 28 | ]) 29 | }); 30 | 31 | test('parse path for all authors', function() { 32 | var path = jp.parse('$..author'); 33 | assert.deepEqual(path, [ 34 | { expression: { type: 'root', value: '$' } }, 35 | { operation: 'member', scope: 'descendant', expression: { type: 'identifier', value: 'author' } } 36 | ]) 37 | }); 38 | 39 | test('parse path for all authors via subscript descendant string literal', function() { 40 | var path = jp.parse("$..['author']"); 41 | assert.deepEqual(path, [ 42 | { expression: { type: 'root', value: '$' } }, 43 | { operation: 'subscript', scope: 'descendant', expression: { type: 'string_literal', value: 'author' } } 44 | ]) 45 | }); 46 | 47 | test('parse path for all things in store', function() { 48 | var path = jp.parse('$.store.*'); 49 | assert.deepEqual(path, [ 50 | { expression: { type: 'root', value: '$' } }, 51 | { operation: 'member', scope: 'child', expression: { type: 'identifier', value: 'store' } }, 52 | { operation: 'member', scope: 'child', expression: { type: 'wildcard', value: '*' } } 53 | ]) 54 | }); 55 | 56 | test('parse path for price of everything in the store', function() { 57 | var path = jp.parse('$.store..price'); 58 | assert.deepEqual(path, [ 59 | { expression: { type: 'root', value: '$' } }, 60 | { operation: 'member', scope: 'child', expression: { type: 'identifier', value: 'store' } }, 61 | { operation: 'member', scope: 'descendant', expression: { type: 'identifier', value: 'price' } } 62 | ]) 63 | }); 64 | 65 | test('parse path for the last book in order via expression', function() { 66 | var path = jp.parse('$..book[(@.length-1)]'); 67 | assert.deepEqual(path, [ 68 | { expression: { type: 'root', value: '$' } }, 69 | { operation: 'member', scope: 'descendant', expression: { type: 'identifier', value: 'book' } }, 70 | { operation: 'subscript', scope: 'child', expression: { type: 'script_expression', value: '(@.length-1)' } } 71 | ]) 72 | }); 73 | 74 | test('parse path for the first two books via union', function() { 75 | var path = jp.parse('$..book[0,1]'); 76 | 77 | assert.deepEqual(path, [ 78 | { expression: { type: 'root', value: '$' } }, 79 | { operation: 'member', scope: 'descendant', expression: { type: 'identifier', value: 'book' } }, 80 | { operation: 'subscript', scope: 'child', expression: { type: 'union', value: [ { expression: { type: 'numeric_literal', value: '0' } }, { expression: { type: 'numeric_literal', value: '1' } } ] } } 81 | ]) 82 | }); 83 | 84 | test('parse path for the first two books via slice', function() { 85 | var path = jp.parse('$..book[0:2]'); 86 | assert.deepEqual(path, [ 87 | { expression: { type: 'root', value: '$' } }, 88 | { operation: 'member', scope: 'descendant', expression: { type: 'identifier', value: 'book' } }, 89 | { operation: 'subscript', scope: 'child', expression: { type: 'slice', value: '0:2' } } 90 | ]) 91 | }); 92 | 93 | test('parse path to filter all books with isbn number', function() { 94 | var path = jp.parse('$..book[?(@.isbn)]'); 95 | assert.deepEqual(path, [ 96 | { expression: { type: 'root', value: '$' } }, 97 | { operation: 'member', scope: 'descendant', expression: { type: 'identifier', value: 'book' } }, 98 | { operation: 'subscript', scope: 'child', expression: { type: 'filter_expression', value: '?(@.isbn)' } } 99 | ]) 100 | }); 101 | 102 | test('parse path to filter all books with a price less than 10', function() { 103 | var path = jp.parse('$..book[?(@.price<10)]'); 104 | assert.deepEqual(path, [ 105 | { expression: { type: 'root', value: '$' } }, 106 | { operation: 'member', scope: 'descendant', expression: { type: 'identifier', value: 'book' } }, 107 | { operation: 'subscript', scope: 'child', expression: { type: 'filter_expression', value: '?(@.price<10)' } } 108 | ]) 109 | }); 110 | 111 | test('parse path to match all elements', function() { 112 | var path = jp.parse('$..*'); 113 | assert.deepEqual(path, [ 114 | { expression: { type: 'root', value: '$' } }, 115 | { operation: 'member', scope: 'descendant', expression: { type: 'wildcard', value: '*' } } 116 | ]) 117 | }); 118 | 119 | test('parse path with leading member', function() { 120 | var path = jp.parse('store'); 121 | assert.deepEqual(path, [ 122 | { operation: 'member', scope: 'child', expression: { type: 'identifier', value: 'store' } } 123 | ]) 124 | }); 125 | 126 | test('parse path with leading member and followers', function() { 127 | var path = jp.parse('Request.prototype.end'); 128 | assert.deepEqual(path, [ 129 | { operation: 'member', scope: 'child', expression: { type: 'identifier', value: 'Request' } }, 130 | { operation: 'member', scope: 'child', expression: { type: 'identifier', value: 'prototype' } }, 131 | { operation: 'member', scope: 'child', expression: { type: 'identifier', value: 'end' } } 132 | ]) 133 | }); 134 | 135 | test('parser ast is reinitialized after parse() throws', function() { 136 | assert.throws(function() { var path = jp.parse('store.book...') }) 137 | var path = jp.parse('$..price'); 138 | assert.deepEqual(path, [ 139 | { "expression": { "type": "root", "value": "$" } }, 140 | { "expression": { "type": "identifier", "value": "price" }, "operation": "member", "scope": "descendant"} 141 | ]) 142 | }); 143 | 144 | }); 145 | 146 | suite('parse-negative', function() { 147 | 148 | test('parse path with leading member component throws', function() { 149 | assert.throws(function(e) { var path = jp.parse('.store') }, /Expecting 'DOLLAR'/) 150 | }); 151 | 152 | test('parse path with leading descendant member throws', function() { 153 | assert.throws(function() { var path = jp.parse('..store') }, /Expecting 'DOLLAR'/) 154 | }); 155 | 156 | test('leading script throws', function() { 157 | assert.throws(function() { var path = jp.parse('()') }, /Unrecognized text/) 158 | }); 159 | 160 | test('first time friendly error', function() { 161 | assert.throws(function() { (new jp.JSONPath).parse('$...') }, /Expecting 'STAR'/) 162 | }); 163 | 164 | }); 165 | -------------------------------------------------------------------------------- /test/query.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var jp = require('../'); 3 | 4 | var data = require('./data/store.json'); 5 | 6 | suite('query', function() { 7 | 8 | test('first-level member', function() { 9 | var results = jp.nodes(data, '$.store'); 10 | assert.deepEqual(results, [ { path: ['$', 'store'], value: data.store } ]); 11 | }); 12 | 13 | test('authors of all books in the store', function() { 14 | var results = jp.nodes(data, '$.store.book[*].author'); 15 | assert.deepEqual(results, [ 16 | { path: ['$', 'store', 'book', 0, 'author'], value: 'Nigel Rees' }, 17 | { path: ['$', 'store', 'book', 1, 'author'], value: 'Evelyn Waugh' }, 18 | { path: ['$', 'store', 'book', 2, 'author'], value: 'Herman Melville' }, 19 | { path: ['$', 'store', 'book', 3, 'author'], value: 'J. R. R. Tolkien' } 20 | ]); 21 | }); 22 | 23 | test('all authors', function() { 24 | var results = jp.nodes(data, '$..author'); 25 | assert.deepEqual(results, [ 26 | { path: ['$', 'store', 'book', 0, 'author'], value: 'Nigel Rees' }, 27 | { path: ['$', 'store', 'book', 1, 'author'], value: 'Evelyn Waugh' }, 28 | { path: ['$', 'store', 'book', 2, 'author'], value: 'Herman Melville' }, 29 | { path: ['$', 'store', 'book', 3, 'author'], value: 'J. R. R. Tolkien' } 30 | ]); 31 | }); 32 | 33 | test('all authors via subscript descendant string literal', function() { 34 | var results = jp.nodes(data, "$..['author']"); 35 | assert.deepEqual(results, [ 36 | { path: ['$', 'store', 'book', 0, 'author'], value: 'Nigel Rees' }, 37 | { path: ['$', 'store', 'book', 1, 'author'], value: 'Evelyn Waugh' }, 38 | { path: ['$', 'store', 'book', 2, 'author'], value: 'Herman Melville' }, 39 | { path: ['$', 'store', 'book', 3, 'author'], value: 'J. R. R. Tolkien' } 40 | ]); 41 | }); 42 | 43 | test('all things in store', function() { 44 | var results = jp.nodes(data, '$.store.*'); 45 | assert.deepEqual(results, [ 46 | { path: ['$', 'store', 'book'], value: data.store.book }, 47 | { path: ['$', 'store', 'bicycle'], value: data.store.bicycle } 48 | ]); 49 | }); 50 | 51 | test('price of everything in the store', function() { 52 | var results = jp.nodes(data, '$.store..price'); 53 | assert.deepEqual(results, [ 54 | { path: ['$', 'store', 'book', 0, 'price'], value: 8.95 }, 55 | { path: ['$', 'store', 'book', 1, 'price'], value: 12.99 }, 56 | { path: ['$', 'store', 'book', 2, 'price'], value: 8.99 }, 57 | { path: ['$', 'store', 'book', 3, 'price'], value: 22.99 }, 58 | { path: ['$', 'store', 'bicycle', 'price'], value: 19.95 } 59 | ]); 60 | }); 61 | 62 | test('last book in order via expression', function() { 63 | var results = jp.nodes(data, '$..book[(@.length-1)]'); 64 | assert.deepEqual(results, [ { path: ['$', 'store', 'book', 3], value: data.store.book[3] }]); 65 | }); 66 | 67 | test('first two books via union', function() { 68 | var results = jp.nodes(data, '$..book[0,1]'); 69 | assert.deepEqual(results, [ 70 | { path: ['$', 'store', 'book', 0], value: data.store.book[0] }, 71 | { path: ['$', 'store', 'book', 1], value: data.store.book[1] } 72 | ]); 73 | }); 74 | 75 | test('first two books via slice', function() { 76 | var results = jp.nodes(data, '$..book[0:2]'); 77 | assert.deepEqual(results, [ 78 | { path: ['$', 'store', 'book', 0], value: data.store.book[0] }, 79 | { path: ['$', 'store', 'book', 1], value: data.store.book[1] } 80 | ]); 81 | }); 82 | 83 | test('filter all books with isbn number', function() { 84 | var results = jp.nodes(data, '$..book[?(@.isbn)]'); 85 | assert.deepEqual(results, [ 86 | { path: ['$', 'store', 'book', 2], value: data.store.book[2] }, 87 | { path: ['$', 'store', 'book', 3], value: data.store.book[3] } 88 | ]); 89 | }); 90 | 91 | test('filter all books with a price less than 10', function() { 92 | var results = jp.nodes(data, '$..book[?(@.price<10)]'); 93 | assert.deepEqual(results, [ 94 | { path: ['$', 'store', 'book', 0], value: data.store.book[0] }, 95 | { path: ['$', 'store', 'book', 2], value: data.store.book[2] } 96 | ]); 97 | }); 98 | 99 | test('first ten of all elements', function() { 100 | var results = jp.nodes(data, '$..*', 10); 101 | assert.deepEqual(results, [ 102 | { path: [ '$', 'store' ], value: data.store }, 103 | { path: [ '$', 'store', 'book' ], value: data.store.book }, 104 | { path: [ '$', 'store', 'bicycle' ], value: data.store.bicycle }, 105 | { path: [ '$', 'store', 'book', 0 ], value: data.store.book[0] }, 106 | { path: [ '$', 'store', 'book', 1 ], value: data.store.book[1] }, 107 | { path: [ '$', 'store', 'book', 2 ], value: data.store.book[2] }, 108 | { path: [ '$', 'store', 'book', 3 ], value: data.store.book[3] }, 109 | { path: [ '$', 'store', 'book', 0, 'category' ], value: 'reference' }, 110 | { path: [ '$', 'store', 'book', 0, 'author' ], value: 'Nigel Rees' }, 111 | { path: [ '$', 'store', 'book', 0, 'title' ], value: 'Sayings of the Century' } 112 | ]) 113 | }); 114 | 115 | test('all elements', function() { 116 | var results = jp.nodes(data, '$..*'); 117 | 118 | assert.deepEqual(results, [ 119 | { path: [ '$', 'store' ], value: data.store }, 120 | { path: [ '$', 'store', 'book' ], value: data.store.book }, 121 | { path: [ '$', 'store', 'bicycle' ], value: data.store.bicycle }, 122 | { path: [ '$', 'store', 'book', 0 ], value: data.store.book[0] }, 123 | { path: [ '$', 'store', 'book', 1 ], value: data.store.book[1] }, 124 | { path: [ '$', 'store', 'book', 2 ], value: data.store.book[2] }, 125 | { path: [ '$', 'store', 'book', 3 ], value: data.store.book[3] }, 126 | { path: [ '$', 'store', 'book', 0, 'category' ], value: 'reference' }, 127 | { path: [ '$', 'store', 'book', 0, 'author' ], value: 'Nigel Rees' }, 128 | { path: [ '$', 'store', 'book', 0, 'title' ], value: 'Sayings of the Century' }, 129 | { path: [ '$', 'store', 'book', 0, 'price' ], value: 8.95 }, 130 | { path: [ '$', 'store', 'book', 1, 'category' ], value: 'fiction' }, 131 | { path: [ '$', 'store', 'book', 1, 'author' ], value: 'Evelyn Waugh' }, 132 | { path: [ '$', 'store', 'book', 1, 'title' ], value: 'Sword of Honour' }, 133 | { path: [ '$', 'store', 'book', 1, 'price' ], value: 12.99 }, 134 | { path: [ '$', 'store', 'book', 2, 'category' ], value: 'fiction' }, 135 | { path: [ '$', 'store', 'book', 2, 'author' ], value: 'Herman Melville' }, 136 | { path: [ '$', 'store', 'book', 2, 'title' ], value: 'Moby Dick' }, 137 | { path: [ '$', 'store', 'book', 2, 'isbn' ], value: '0-553-21311-3' }, 138 | { path: [ '$', 'store', 'book', 2, 'price' ], value: 8.99 }, 139 | { path: [ '$', 'store', 'book', 3, 'category' ], value: 'fiction' }, 140 | { path: [ '$', 'store', 'book', 3, 'author' ], value: 'J. R. R. Tolkien' }, 141 | { path: [ '$', 'store', 'book', 3, 'title' ], value: 'The Lord of the Rings' }, 142 | { path: [ '$', 'store', 'book', 3, 'isbn' ], value: '0-395-19395-8' }, 143 | { path: [ '$', 'store', 'book', 3, 'price' ], value: 22.99 }, 144 | { path: [ '$', 'store', 'bicycle', 'color' ], value: 'red' }, 145 | { path: [ '$', 'store', 'bicycle', 'price' ], value: 19.95 } 146 | ]); 147 | }); 148 | 149 | test('all elements via subscript wildcard', function() { 150 | var results = jp.nodes(data, '$..*'); 151 | assert.deepEqual(jp.nodes(data, '$..[*]'), jp.nodes(data, '$..*')); 152 | }); 153 | 154 | test('object subscript wildcard', function() { 155 | var results = jp.query(data, '$.store[*]'); 156 | assert.deepEqual(results, [ data.store.book, data.store.bicycle ]); 157 | }); 158 | 159 | test('no match returns empty array', function() { 160 | var results = jp.nodes(data, '$..bookz'); 161 | assert.deepEqual(results, []); 162 | }); 163 | 164 | test('member numeric literal gets first element', function() { 165 | var results = jp.nodes(data, '$.store.book.0'); 166 | assert.deepEqual(results, [ { path: [ '$', 'store', 'book', 0 ], value: data.store.book[0] } ]); 167 | }); 168 | 169 | test('member numeric literal matches string-numeric key', function() { 170 | var data = { authors: { '1': 'Herman Melville', '2': 'J. R. R. Tolkien' } }; 171 | var results = jp.nodes(data, '$.authors.1'); 172 | assert.deepEqual(results, [ { path: [ '$', 'authors', 1 ], value: 'Herman Melville' } ]); 173 | }); 174 | 175 | test('descendant numeric literal gets first element', function() { 176 | var results = jp.nodes(data, '$.store.book..0'); 177 | assert.deepEqual(results, [ { path: [ '$', 'store', 'book', 0 ], value: data.store.book[0] } ]); 178 | }); 179 | 180 | test('root element gets us original obj', function() { 181 | var results = jp.nodes(data, '$'); 182 | assert.deepEqual(results, [ { path: ['$'], value: data } ]); 183 | }); 184 | 185 | test('subscript double-quoted string', function() { 186 | var results = jp.nodes(data, '$["store"]'); 187 | assert.deepEqual(results, [ { path: ['$', 'store'], value: data.store} ]); 188 | }); 189 | 190 | test('subscript single-quoted string', function() { 191 | var results = jp.nodes(data, "$['store']"); 192 | assert.deepEqual(results, [ { path: ['$', 'store'], value: data.store} ]); 193 | }); 194 | 195 | test('leading member component', function() { 196 | var results = jp.nodes(data, "store"); 197 | assert.deepEqual(results, [ { path: ['$', 'store'], value: data.store} ]); 198 | }); 199 | 200 | test('union of three array slices', function() { 201 | var results = jp.query(data, "$.store.book[0:1,1:2,2:3]"); 202 | assert.deepEqual(results, data.store.book.slice(0,3)); 203 | }); 204 | 205 | test('slice with step > 1', function() { 206 | var results = jp.query(data, "$.store.book[0:4:2]"); 207 | assert.deepEqual(results, [ data.store.book[0], data.store.book[2]]); 208 | }); 209 | 210 | test('union of subscript string literal keys', function() { 211 | var results = jp.nodes(data, "$.store['book','bicycle']"); 212 | assert.deepEqual(results, [ 213 | { path: ['$', 'store', 'book'], value: data.store.book }, 214 | { path: ['$', 'store', 'bicycle'], value: data.store.bicycle }, 215 | ]); 216 | }); 217 | 218 | test('union of subscript string literal three keys', function() { 219 | var results = jp.nodes(data, "$.store.book[0]['title','author','price']"); 220 | assert.deepEqual(results, [ 221 | { path: ['$', 'store', 'book', 0, 'title'], value: data.store.book[0].title }, 222 | { path: ['$', 'store', 'book', 0, 'author'], value: data.store.book[0].author }, 223 | { path: ['$', 'store', 'book', 0, 'price'], value: data.store.book[0].price } 224 | ]); 225 | }); 226 | 227 | test('union of subscript integer three keys followed by member-child-identifier', function() { 228 | var results = jp.nodes(data, "$.store.book[1,2,3]['title']"); 229 | assert.deepEqual(results, [ 230 | { path: ['$', 'store', 'book', 1, 'title'], value: data.store.book[1].title }, 231 | { path: ['$', 'store', 'book', 2, 'title'], value: data.store.book[2].title }, 232 | { path: ['$', 'store', 'book', 3, 'title'], value: data.store.book[3].title } 233 | ]); 234 | }); 235 | 236 | test('union of subscript integer three keys followed by union of subscript string literal three keys', function() { 237 | var results = jp.nodes(data, "$.store.book[0,1,2,3]['title','author','price']"); 238 | assert.deepEqual(results, [ 239 | { path: ['$', 'store', 'book', 0, 'title'], value: data.store.book[0].title }, 240 | { path: ['$', 'store', 'book', 0, 'author'], value: data.store.book[0].author }, 241 | { path: ['$', 'store', 'book', 0, 'price'], value: data.store.book[0].price }, 242 | { path: ['$', 'store', 'book', 1, 'title'], value: data.store.book[1].title }, 243 | { path: ['$', 'store', 'book', 1, 'author'], value: data.store.book[1].author }, 244 | { path: ['$', 'store', 'book', 1, 'price'], value: data.store.book[1].price }, 245 | { path: ['$', 'store', 'book', 2, 'title'], value: data.store.book[2].title }, 246 | { path: ['$', 'store', 'book', 2, 'author'], value: data.store.book[2].author }, 247 | { path: ['$', 'store', 'book', 2, 'price'], value: data.store.book[2].price }, 248 | { path: ['$', 'store', 'book', 3, 'title'], value: data.store.book[3].title }, 249 | { path: ['$', 'store', 'book', 3, 'author'], value: data.store.book[3].author }, 250 | { path: ['$', 'store', 'book', 3, 'price'], value: data.store.book[3].price } 251 | ]); 252 | }); 253 | 254 | test('union of subscript integer four keys, including an inexistent one, followed by union of subscript string literal three keys', function() { 255 | var results = jp.nodes(data, "$.store.book[0,1,2,3,151]['title','author','price']"); 256 | assert.deepEqual(results, [ 257 | { path: ['$', 'store', 'book', 0, 'title'], value: data.store.book[0].title }, 258 | { path: ['$', 'store', 'book', 0, 'author'], value: data.store.book[0].author }, 259 | { path: ['$', 'store', 'book', 0, 'price'], value: data.store.book[0].price }, 260 | { path: ['$', 'store', 'book', 1, 'title'], value: data.store.book[1].title }, 261 | { path: ['$', 'store', 'book', 1, 'author'], value: data.store.book[1].author }, 262 | { path: ['$', 'store', 'book', 1, 'price'], value: data.store.book[1].price }, 263 | { path: ['$', 'store', 'book', 2, 'title'], value: data.store.book[2].title }, 264 | { path: ['$', 'store', 'book', 2, 'author'], value: data.store.book[2].author }, 265 | { path: ['$', 'store', 'book', 2, 'price'], value: data.store.book[2].price }, 266 | { path: ['$', 'store', 'book', 3, 'title'], value: data.store.book[3].title }, 267 | { path: ['$', 'store', 'book', 3, 'author'], value: data.store.book[3].author }, 268 | { path: ['$', 'store', 'book', 3, 'price'], value: data.store.book[3].price } 269 | ]); 270 | }); 271 | 272 | test('union of subscript integer three keys followed by union of subscript string literal three keys, followed by inexistent literal key', function() { 273 | var results = jp.nodes(data, "$.store.book[0,1,2,3]['title','author','price','fruit']"); 274 | assert.deepEqual(results, [ 275 | { path: ['$', 'store', 'book', 0, 'title'], value: data.store.book[0].title }, 276 | { path: ['$', 'store', 'book', 0, 'author'], value: data.store.book[0].author }, 277 | { path: ['$', 'store', 'book', 0, 'price'], value: data.store.book[0].price }, 278 | { path: ['$', 'store', 'book', 1, 'title'], value: data.store.book[1].title }, 279 | { path: ['$', 'store', 'book', 1, 'author'], value: data.store.book[1].author }, 280 | { path: ['$', 'store', 'book', 1, 'price'], value: data.store.book[1].price }, 281 | { path: ['$', 'store', 'book', 2, 'title'], value: data.store.book[2].title }, 282 | { path: ['$', 'store', 'book', 2, 'author'], value: data.store.book[2].author }, 283 | { path: ['$', 'store', 'book', 2, 'price'], value: data.store.book[2].price }, 284 | { path: ['$', 'store', 'book', 3, 'title'], value: data.store.book[3].title }, 285 | { path: ['$', 'store', 'book', 3, 'author'], value: data.store.book[3].author }, 286 | { path: ['$', 'store', 'book', 3, 'price'], value: data.store.book[3].price } 287 | ]); 288 | }); 289 | 290 | test('union of subscript 4 array slices followed by union of subscript string literal three keys', function() { 291 | var results = jp.nodes(data, "$.store.book[0:1,1:2,2:3,3:4]['title','author','price']"); 292 | assert.deepEqual(results, [ 293 | { path: ['$', 'store', 'book', 0, 'title'], value: data.store.book[0].title }, 294 | { path: ['$', 'store', 'book', 0, 'author'], value: data.store.book[0].author }, 295 | { path: ['$', 'store', 'book', 0, 'price'], value: data.store.book[0].price }, 296 | { path: ['$', 'store', 'book', 1, 'title'], value: data.store.book[1].title }, 297 | { path: ['$', 'store', 'book', 1, 'author'], value: data.store.book[1].author }, 298 | { path: ['$', 'store', 'book', 1, 'price'], value: data.store.book[1].price }, 299 | { path: ['$', 'store', 'book', 2, 'title'], value: data.store.book[2].title }, 300 | { path: ['$', 'store', 'book', 2, 'author'], value: data.store.book[2].author }, 301 | { path: ['$', 'store', 'book', 2, 'price'], value: data.store.book[2].price }, 302 | { path: ['$', 'store', 'book', 3, 'title'], value: data.store.book[3].title }, 303 | { path: ['$', 'store', 'book', 3, 'author'], value: data.store.book[3].author }, 304 | { path: ['$', 'store', 'book', 3, 'price'], value: data.store.book[3].price } 305 | ]); 306 | }); 307 | 308 | 309 | test('nested parentheses eval', function() { 310 | var pathExpression = '$..book[?( @.price && (@.price + 20 || false) )]' 311 | var results = jp.query(data, pathExpression); 312 | assert.deepEqual(results, data.store.book); 313 | }); 314 | 315 | test('array indexes from 0 to 100', function() { 316 | var data = []; 317 | for (var i = 0; i <= 100; ++i) 318 | data[i] = Math.random(); 319 | 320 | for (var i = 0; i <= 100; ++i) { 321 | var results = jp.query(data, '$[' + i.toString() + ']'); 322 | assert.deepEqual(results, [data[i]]); 323 | } 324 | }); 325 | 326 | test('descendant subscript numeric literal', function() { 327 | var data = [ 0, [ 1, 2, 3 ], [ 4, 5, 6 ] ]; 328 | var results = jp.query(data, '$..[0]'); 329 | assert.deepEqual(results, [ 0, 1, 4 ]); 330 | }); 331 | 332 | test('descendant subscript numeric literal', function() { 333 | var data = [ 0, 1, [ 2, 3, 4 ], [ 5, 6, 7, [ 8, 9 , 10 ] ] ]; 334 | var results = jp.query(data, '$..[0,1]'); 335 | assert.deepEqual(results, [ 0, 1, 2, 3, 5, 6, 8, 9 ]); 336 | }); 337 | 338 | test('throws for no input', function() { 339 | assert.throws(function() { jp.query() }, /needs to be an object/); 340 | }); 341 | 342 | test('throws for bad input', function() { 343 | assert.throws(function() { jp.query("string", "string") }, /needs to be an object/); 344 | }); 345 | 346 | test('throws for bad input', function() { 347 | assert.throws(function() { jp.query({}, null) }, /we need a path/); 348 | }); 349 | 350 | test('throws for bad input', function() { 351 | assert.throws(function() { jp.query({}, 42) }, /we need a path/); 352 | }); 353 | 354 | test('union on objects', function() { 355 | assert.deepEqual(jp.query({a: 1, b: 2, c: null}, '$..["a","b","c","d"]'), [1, 2, null]); 356 | }); 357 | 358 | }); 359 | 360 | -------------------------------------------------------------------------------- /test/slice.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var slice = require('../lib/slice'); 3 | 4 | var data = ['a', 'b', 'c', 'd', 'e', 'f']; 5 | 6 | suite('slice', function() { 7 | 8 | test('no params yields copy', function() { 9 | assert.deepEqual(slice(data), data); 10 | }); 11 | 12 | test('no end param defaults to end', function() { 13 | assert.deepEqual(slice(data, 2), data.slice(2)); 14 | }); 15 | 16 | test('zero end param yields empty', function() { 17 | assert.deepEqual(slice(data, 0, 0), []); 18 | }); 19 | 20 | test('first element with explicit params', function() { 21 | assert.deepEqual(slice(data, 0, 1, 1), ['a']); 22 | }); 23 | 24 | test('last element with explicit params', function() { 25 | assert.deepEqual(slice(data, -1, 6), ['f']); 26 | }); 27 | 28 | test('empty extents and negative step reverses', function() { 29 | assert.deepEqual(slice(data, null, null, -1), ['f', 'e', 'd', 'c', 'b', 'a']); 30 | }); 31 | 32 | test('negative step partial slice', function() { 33 | assert.deepEqual(slice(data, 4, 2, -1), ['e', 'd']); 34 | }); 35 | 36 | test('negative step partial slice no start defaults to end', function() { 37 | assert.deepEqual(slice(data, null, 2, -1), ['f', 'e', 'd']); 38 | }); 39 | 40 | test('extents clamped end', function() { 41 | assert.deepEqual(slice(data, null, 100), data); 42 | }); 43 | 44 | test('extents clamped beginning', function() { 45 | assert.deepEqual(slice(data, -100, 100), data); 46 | }); 47 | 48 | test('backwards extents yields empty', function() { 49 | assert.deepEqual(slice(data, 2, 1), []); 50 | }); 51 | 52 | test('zero step gets shot down', function() { 53 | assert.throws(function() { slice(data, null, null, 0) }); 54 | }); 55 | 56 | }); 57 | 58 | -------------------------------------------------------------------------------- /test/stringify.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var jp = require('../'); 3 | 4 | suite('stringify', function() { 5 | 6 | test('simple path stringifies', function() { 7 | var string = jp.stringify(['$', 'a', 'b', 'c']); 8 | assert.equal(string, '$.a.b.c'); 9 | }); 10 | 11 | test('numeric literals end up as subscript numbers', function() { 12 | var string = jp.stringify(['$', 'store', 'book', 0, 'author']); 13 | assert.equal(string, '$.store.book[0].author'); 14 | }); 15 | 16 | test('simple path with no leading root stringifies', function() { 17 | var string = jp.stringify(['a', 'b', 'c']); 18 | assert.equal(string, '$.a.b.c'); 19 | }); 20 | 21 | test('simple parsed path stringifies', function() { 22 | var path = [ 23 | { scope: 'child', operation: 'member', expression: { type: 'identifier', value: 'a' } }, 24 | { scope: 'child', operation: 'member', expression: { type: 'identifier', value: 'b' } }, 25 | { scope: 'child', operation: 'member', expression: { type: 'identifier', value: 'c' } } 26 | ]; 27 | var string = jp.stringify(path); 28 | assert.equal(string, '$.a.b.c'); 29 | }); 30 | 31 | test('keys with hyphens get subscripted', function() { 32 | var string = jp.stringify(['$', 'member-search']); 33 | assert.equal(string, '$["member-search"]'); 34 | }); 35 | 36 | test('complicated path round trips', function() { 37 | var pathExpression = '$..*[0:2].member["string-xyz"]'; 38 | var path = jp.parse(pathExpression); 39 | var string = jp.stringify(path); 40 | assert.equal(string, pathExpression); 41 | }); 42 | 43 | test('complicated path with filter exp round trips', function() { 44 | var pathExpression = '$..*[0:2].member[?(@.val > 10)]'; 45 | var path = jp.parse(pathExpression); 46 | var string = jp.stringify(path); 47 | assert.equal(string, pathExpression); 48 | }); 49 | 50 | test('throws for no input', function() { 51 | assert.throws(function() { jp.stringify() }, /we need a path/); 52 | }); 53 | 54 | }); 55 | -------------------------------------------------------------------------------- /test/sugar.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var jp = require('../'); 3 | var util = require('util'); 4 | 5 | suite('sugar', function() { 6 | 7 | test('parent gets us parent value', function() { 8 | var data = { a: 1, b: 2, c: 3, z: { a: 100, b: 200 } }; 9 | var parent = jp.parent(data, '$.z.b'); 10 | assert.equal(parent, data.z); 11 | }); 12 | 13 | test('apply method sets values', function() { 14 | var data = { a: 1, b: 2, c: 3, z: { a: 100, b: 200 } }; 15 | jp.apply(data, '$..a', function(v) { return v + 1 }); 16 | assert.equal(data.a, 2); 17 | assert.equal(data.z.a, 101); 18 | }); 19 | 20 | test('apply method applies survives structural changes', function() { 21 | var data = {a: {b: [1, {c: [2,3]}]}}; 22 | jp.apply(data, '$..*[?(@.length > 1)]', function(array) { 23 | return array.reverse(); 24 | }); 25 | assert.deepEqual(data.a.b, [{c: [3, 2]}, 1]); 26 | }); 27 | 28 | test('value method gets us a value', function() { 29 | var data = { a: 1, b: 2, c: 3, z: { a: 100, b: 200 } }; 30 | var b = jp.value(data, '$..b') 31 | assert.equal(b, data.b); 32 | }); 33 | 34 | test('value method sets us a value', function() { 35 | var data = { a: 1, b: 2, c: 3, z: { a: 100, b: 200 } }; 36 | var b = jp.value(data, '$..b', '5000') 37 | assert.equal(b, 5000); 38 | assert.equal(data.b, 5000); 39 | }); 40 | 41 | test('value method sets new key and value', function() { 42 | var data = {}; 43 | var a = jp.value(data, '$.a', 1); 44 | var c = jp.value(data, '$.b.c', 2); 45 | assert.equal(a, 1); 46 | assert.equal(data.a, 1); 47 | assert.equal(c, 2); 48 | assert.equal(data.b.c, 2); 49 | }); 50 | 51 | test('value method sets new array value', function() { 52 | var data = {}; 53 | var v1 = jp.value(data, '$.a.d[0]', 4); 54 | var v2 = jp.value(data, '$.a.d[1]', 5); 55 | assert.equal(v1, 4); 56 | assert.equal(v2, 5); 57 | assert.deepEqual(data.a.d, [4, 5]); 58 | }); 59 | 60 | test('value method sets non-literal key', function() { 61 | var data = { "list": [ { "index": 0, "value": "default" }, { "index": 1, "value": "default" } ] }; 62 | jp.value(data, '$.list[?(@.index == 1)].value', "test"); 63 | assert.equal(data.list[1].value, "test"); 64 | }); 65 | 66 | test('paths with a count gets us back count many paths', function() { 67 | data = [ { a: [ 1, 2, 3 ], b: [ -1, -2, -3 ] }, { } ] 68 | paths = jp.paths(data, '$..*', 3) 69 | assert.deepEqual(paths, [ ['$', '0'], ['$', '1'], ['$', '0', 'a'] ]); 70 | }); 71 | 72 | }); 73 | --------------------------------------------------------------------------------