diff --git a/lib/parser.js b/lib/parser.js index 7fa2fc58..cb71c68e 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -102,7 +102,7 @@ }; Parser.prototype.assignOrPush = function(obj, key, newValue) { - if (!(key in obj)) { + if (!Object.prototype.hasOwnProperty.call(obj, key)) { if (!this.options.explicitArray) { return defineProperty(obj, key, newValue); } else { diff --git a/src/parser.coffee b/src/parser.coffee index dade8f39..9eda8f30 100644 --- a/src/parser.coffee +++ b/src/parser.coffee @@ -61,7 +61,7 @@ class exports.Parser extends events @emit err assignOrPush: (obj, key, newValue) => - if key not of obj + if not Object::hasOwnProperty.call obj, key if not @options.explicitArray defineProperty obj, key, newValue else diff --git a/test/parser.test.coffee b/test/parser.test.coffee index f2758759..af132a4e 100644 --- a/test/parser.test.coffee +++ b/test/parser.test.coffee @@ -647,3 +647,23 @@ module.exports = .catch (err) -> assert.notEqual err, null test.finish() + + # Regression test for issue #719: prototype chain property confusion + # Tags named after Object.prototype methods should parse correctly + 'test prototype property names do not cause errors': skeleton({__xmlString: 'value1value2value3value4'}, (r) -> + console.log 'Result object: ' + util.inspect r, false, 10 + # Verify all prototype-named tags parsed as strings, not functions + equ r.root.toString[0], 'value1' + equ r.root.valueOf[0], 'value2' + equ r.root.constructor[0], 'value3' + equ r.root.hasOwnProperty[0], 'value4' + # Verify no inherited functions leaked into the result + equ typeof r.root.toString[0], 'string' + equ typeof r.root.valueOf[0], 'string') + + 'test multiple prototype property tags parse correctly': skeleton({__xmlString: 'ab'}, (r) -> + console.log 'Result object: ' + util.inspect r, false, 10 + # Multiple tags with prototype names should be collected into arrays + equ r.root.toString.length, 2 + equ r.root.toString[0], 'a' + equ r.root.toString[1], 'b')