Skip to content

Commit

Permalink
Restrict duplicated mapping keys with exception for merged keys
Browse files Browse the repository at this point in the history
Fixes #166
  • Loading branch information
dervus committed Jan 9, 2016
1 parent 0fbab05 commit 9ea29ec
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 10 deletions.
30 changes: 20 additions & 10 deletions lib/js-yaml/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ function State(input, options) {
this.schema = options['schema'] || DEFAULT_FULL_SCHEMA;
this.onWarning = options['onWarning'] || null;
this.legacy = options['legacy'] || false;
this.json = options['json'] || false;

this.implicitTypes = this.schema.compiledImplicit;
this.typeMap = this.schema.compiledTypeMap;
Expand Down Expand Up @@ -260,7 +261,7 @@ function captureSegment(state, start, end, checkJson) {
}
}

function mergeMappings(state, destination, source) {
function mergeMappings(state, destination, source, overridableKeys) {
var sourceKeys, key, index, quantity;

if (!common.isObject(source)) {
Expand All @@ -274,11 +275,12 @@ function mergeMappings(state, destination, source) {

if (!_hasOwnProperty.call(destination, key)) {
destination[key] = source[key];
overridableKeys[key] = true;
}
}
}

function storeMappingPair(state, _result, keyTag, keyNode, valueNode) {
function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode) {
var index, quantity;

keyNode = String(keyNode);
Expand All @@ -290,13 +292,19 @@ function storeMappingPair(state, _result, keyTag, keyNode, valueNode) {
if ('tag:yaml.org,2002:merge' === keyTag) {
if (Array.isArray(valueNode)) {
for (index = 0, quantity = valueNode.length; index < quantity; index += 1) {
mergeMappings(state, _result, valueNode[index]);
mergeMappings(state, _result, valueNode[index], overridableKeys);
}
} else {
mergeMappings(state, _result, valueNode);
mergeMappings(state, _result, valueNode, overridableKeys);
}
} else {
if (!state.json &&
!_hasOwnProperty.call(overridableKeys, keyNode) &&
_hasOwnProperty.call(_result, keyNode)) {
throwError(state, 'duplicated mapping key');
}
_result[keyNode] = valueNode;
delete overridableKeys[keyNode];
}

return _result;
Expand Down Expand Up @@ -636,6 +644,7 @@ function readFlowCollection(state, nodeIndent) {
isPair,
isExplicitPair,
isMapping,
overridableKeys = {},
keyNode,
keyTag,
valueNode,
Expand Down Expand Up @@ -707,9 +716,9 @@ function readFlowCollection(state, nodeIndent) {
}

if (isMapping) {
storeMappingPair(state, _result, keyTag, keyNode, valueNode);
storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode);
} else if (isPair) {
_result.push(storeMappingPair(state, null, keyTag, keyNode, valueNode));
_result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode));
} else {
_result.push(keyNode);
}
Expand Down Expand Up @@ -941,6 +950,7 @@ function readBlockMapping(state, nodeIndent, flowIndent) {
_tag = state.tag,
_anchor = state.anchor,
_result = {},
overridableKeys = {},
keyTag = null,
keyNode = null,
valueNode = null,
Expand All @@ -966,7 +976,7 @@ function readBlockMapping(state, nodeIndent, flowIndent) {

if (0x3F/* ? */ === ch) {
if (atExplicitKey) {
storeMappingPair(state, _result, keyTag, keyNode, null);
storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null);
keyTag = keyNode = valueNode = null;
}

Expand Down Expand Up @@ -1006,7 +1016,7 @@ function readBlockMapping(state, nodeIndent, flowIndent) {
}

if (atExplicitKey) {
storeMappingPair(state, _result, keyTag, keyNode, null);
storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null);
keyTag = keyNode = valueNode = null;
}

Expand Down Expand Up @@ -1051,7 +1061,7 @@ function readBlockMapping(state, nodeIndent, flowIndent) {
}

if (!atExplicitKey) {
storeMappingPair(state, _result, keyTag, keyNode, valueNode);
storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode);
keyTag = keyNode = valueNode = null;
}

Expand All @@ -1072,7 +1082,7 @@ function readBlockMapping(state, nodeIndent, flowIndent) {

// Special case: last mapping's node contains only the key in explicit notation.
if (atExplicitKey) {
storeMappingPair(state, _result, keyTag, keyNode, null);
storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null);
}

// Expose the resulting mapping.
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 9ea29ec

Please sign in to comment.