diff --git a/src/functions.js b/src/functions.js index 2c6ae16a..667d878a 100644 --- a/src/functions.js +++ b/src/functions.js @@ -1698,7 +1698,7 @@ const functions = (() => { } } } - } else if (input !== null && typeof input === 'object' && !isFunction(input)) { + } else if (input !== null && typeof input === 'object' && Object.prototype.hasOwnProperty.call(input, key) && !isFunction(input)) { result = input[key]; } return result; diff --git a/src/jsonata.js b/src/jsonata.js index c21eb1e2..97e8be56 100644 --- a/src/jsonata.js +++ b/src/jsonata.js @@ -1293,13 +1293,6 @@ var jsonata = (function() { } for(var ii = 0; ii < matches.length; ii++) { var match = matches[ii]; - if (match && (match.isPrototypeOf(result) || match instanceof Object.constructor)) { - throw { - code: "D1010", - stack: (new Error()).stack, - position: expr.position - }; - } // evaluate the update value for each match var update = await evaluate(expr.update, match, environment); // update must be an object @@ -1989,7 +1982,6 @@ var jsonata = (function() { "T1007": "Attempted to partially apply a non-function. Did you mean ${{{token}}}?", "T1008": "Attempted to partially apply a non-function", "D1009": "Multiple key definitions evaluate to same key: {{value}}", - "D1010": "Attempted to access the Javascript object prototype", // Javascript specific "T1010": "The matcher function argument passed to function {{token}} does not return the correct object structure", "T2001": "The left side of the {{token}} operator must evaluate to a number", "T2002": "The right side of the {{token}} operator must evaluate to a number", diff --git a/test/implementation-tests.js b/test/implementation-tests.js index 784d9b67..80ed604b 100644 --- a/test/implementation-tests.js +++ b/test/implementation-tests.js @@ -955,33 +955,45 @@ describe("Tests that are specific to a Javascript runtime", () => { }); }); }); - describe("Expressions that attempt to pollute the object prototype", function() { - it("should throw an error with __proto__", async function() { - const expr = jsonata('{} ~> | __proto__ | {"is_admin": true} |'); + + describe("Expressions that attempt to access the object prototype", function() { + const data = {"foo": {"bar": "baz"}}; + it("should ignore __proto__", async function() { + const expr = jsonata('foo.__proto__'); + const result = await expr.evaluate(data); + expect(result).to.deep.equal(undefined); + }); + + it("should throw an error trying to invoke toString()", async function() { + const expr = jsonata('foo.toString()'); expect( - expr.evaluate() + expr.evaluate(data) ).to.eventually.be.rejected.to.deep.contain({ - position: 7, - code: "D1010", + position: 13, + code: "T1006", }); }); + }); + + describe("Expressions that attempt to pollute the object prototype", function() { + it("should ignore __proto__", async function() { + const expr = jsonata('{} ~> | __proto__ | {"is_admin": true} |'); + const result = await expr.evaluate(); + expect(result).to.deep.equal({}); + }); it("should throw an error with __lookupGetter__", async function() { const expr = jsonata('{} ~> | __lookupGetter__("__proto__")() | {"is_admin": true} |'); expect( expr.evaluate() ).to.eventually.be.rejected.to.deep.contain({ - position: 7, - code: "D1010", + position: 25, + code: "T1006", }); }); - it("should throw an error with constructor", async function() { + it("should ignore constructor", async function() { const expr = jsonata('{} ~> | constructor | {"is_admin": true} |'); - expect( - expr.evaluate() - ).to.eventually.be.rejected.to.deep.contain({ - position: 7, - code: "D1010", - }); + const result = await expr.evaluate(); + expect(result).to.deep.equal({}); }); }); });