From dbbd94d5dbdec5e8083e34d2be4b85b2aed0e50b Mon Sep 17 00:00:00 2001
From: Adam Powers <apowers@ato.ms>
Date: Sun, 16 Aug 2015 23:37:40 -0700
Subject: [PATCH] Fixes s3u/JSONPath#49 - parsing error when bracket paths
 contain dot

Added six new tests for various path formats:
$.store.book[*].author
$['store']['book'][*]['author']
$[store][book][*][author]
$.store.book[*]['author']
$['store']['book'][*]['application/vnd.wordperfect']
$.store.book[*]['vnd.wordperfect']

Prior to fixing a regular expression in the _normalize() function, the
last two tests would fail due to the '.' in the bracket path
'vnd.wordperfect'. This is fixed by adding a negative forward
lookahead (?![^\[]*\]) to the regular expression identifying '.'. The
new negative forward lookahead assumes that any '.' before a '[' is
okay, but any '.' before a ']' must be inside a bracket set and should
be ignored.
---
 lib/jsonpath.js               |   2 +-
 test/test.path_expressions.js | 113 ++++++++++++++++++++++++++++++++++
 2 files changed, 114 insertions(+), 1 deletion(-)
 create mode 100644 test/test.path_expressions.js

diff --git a/lib/jsonpath.js b/lib/jsonpath.js
index 28e0737..578901f 100644
--- a/lib/jsonpath.js
+++ b/lib/jsonpath.js
@@ -92,7 +92,7 @@ JSONPath.prototype._normalize = function (expr) {
     if (cache[expr]) {return cache[expr];}
     var subx = [];
     var normalized = expr.replace(/[\['](\??\(.*?\))[\]']/g, function ($0, $1) {return '[#' + (subx.push($1) - 1) + ']';})
-                    .replace(/'?\.'?|\['?/g, ';')
+                    .replace(/'?\.'?(?![^\[]*\])|\['?/g, ';')
                     .replace(/(?:;)?(\^+)(?:;)?/g, function ($0, ups) {return ';' + ups.split('').join(';') + ';';})
                     .replace(/;;;|;;/g, ';..;')
                     .replace(/;$|'?\]|'$/g, '');
diff --git a/test/test.path_expressions.js b/test/test.path_expressions.js
new file mode 100644
index 0000000..0418038
--- /dev/null
+++ b/test/test.path_expressions.js
@@ -0,0 +1,113 @@
+var JSONPath = require('../'),
+    testCase = require('nodeunit').testCase
+
+// tests based on examples at http://goessner.net/articles/JsonPath/
+
+var json = {"store": {
+    "book": [
+      { "category": "reference",
+        "author": "Nigel Rees",
+        "application/vnd.wordperfect": "sotc.wpd",
+        "title": "Sayings of the Century",
+        "price": 8.95
+      },
+      { "category": "fiction",
+        "author": "Evelyn Waugh",
+        "title": "Sword of Honour",
+        "price": 12.99
+      },
+      { "category": "fiction",
+        "author": "Herman Melville",
+        "title": "Moby Dick",
+        "isbn": "0-553-21311-3",
+        "price": 8.99
+      },
+      { "category": "fiction",
+        "author": "J. R. R. Tolkien",
+        "title": "The Lord of the Rings",
+        "isbn": "0-395-19395-8",
+        "price": 22.99
+      }
+    ],
+    "bicycle": {
+      "color": "red",
+      "price": 19.95
+    }
+  }
+};
+
+
+module.exports = testCase({
+
+    // ============================================================================
+    'dot notation': function(test) {
+    // ============================================================================
+        test.expect(1);
+        var books = json.store.book;
+        var expected = [books[0].author, books[1].author, books[2].author, books[3].author];
+        var result = JSONPath({json: json, path: '$.store.book[*].author'});
+        test.deepEqual(expected, result);
+
+        test.done();
+    },
+
+    // ============================================================================
+    'bracket notation': function(test) {
+    // ============================================================================
+        test.expect(1);
+        var books = json.store.book;
+        var expected = [books[0].author, books[1].author, books[2].author, books[3].author];
+        var result = JSONPath({json: json, path: "$['store']['book'][*]['author']"});
+        test.deepEqual(expected, result);
+
+        test.done();
+    },
+
+    // ============================================================================
+    'bracket notation without quotes': function(test) {
+    // ============================================================================
+        test.expect(1);
+        var books = json.store.book;
+        var expected = [books[0].author, books[1].author, books[2].author, books[3].author];
+        var result = JSONPath({json: json, path: "$[store][book][*][author]"});
+        test.deepEqual(expected, result);
+
+        test.done();
+    },
+
+    // ============================================================================
+    'mixed notation': function(test) {
+    // ============================================================================
+        test.expect(1);
+        var books = json.store.book;
+        var expected = [books[0].author, books[1].author, books[2].author, books[3].author];
+        var result = JSONPath({json: json, path: "$.store.book[*]['author']"});
+        test.deepEqual(expected, result);
+
+        test.done();
+    },
+
+    // ============================================================================
+    'bracket notation containing dots': function(test) {
+    // ============================================================================
+        test.expect(1);
+        var books = json.store.book;
+        var expected = [books[0]["application/vnd.wordperfect"]];
+        var result = JSONPath({json: json, path: "$['store']['book'][*]['application/vnd.wordperfect']"});
+        test.deepEqual(expected, result);
+
+        test.done();
+    },
+
+    // ============================================================================
+    'mixed notation continaing dots': function(test) {
+    // ============================================================================
+        test.expect(1);
+        var books = json.store.book;
+        var expected = [books[0]["application/vnd.wordperfect"]];
+        var result = JSONPath({json: json, path: "$.store.book[*]['application/vnd.wordperfect']"});
+        test.deepEqual(expected, result);
+
+        test.done();
+    },
+});
-- 
GitLab