diff --git a/modules/core/difference.js b/modules/core/difference.js index 726060aa4..425540226 100644 --- a/modules/core/difference.js +++ b/modules/core/difference.js @@ -73,14 +73,30 @@ export function coreDifference(base, head) { _diff.didChange = _didChange; - _diff.extantIDs = function extantIDs() { - var result = []; + // pass true to include affected relation members + _diff.extantIDs = function extantIDs(includeRelMembers) { + var result = new Set(); Object.keys(_changes).forEach(function(id) { if (_changes[id].head) { - result.push(id); + result.add(id); + } + + var h = _changes[id].head; + var b = _changes[id].base; + var entity = h || b; + + if (includeRelMembers && entity.type === 'relation') { + var mh = h ? h.members.map(function(m) { return m.id; }) : []; + var mb = b ? b.members.map(function(m) { return m.id; }) : []; + utilArrayUnion(mh, mb).forEach(function(memberID) { + if (head.hasEntity(memberID)) { + result.add(memberID); + } + }); } }); - return result; + + return Array.from(result); }; diff --git a/modules/core/validator.js b/modules/core/validator.js index e85240e3d..73dbe93b5 100644 --- a/modules/core/validator.js +++ b/modules/core/validator.js @@ -292,8 +292,12 @@ export function coreValidator(context) { if (entity.type === 'node') { // include parent ways graph.parentWays(entity).forEach(function(parentWay) { - checkParentRels.push(parentWay); acc.add(parentWay.id); + checkParentRels.push(parentWay); + }); + } else if (entity.type === 'relation') { // include members + entity.members.forEach(function(member) { + acc.add(member.id); }); } @@ -356,8 +360,8 @@ export function coreValidator(context) { } } - var entityIDs = difference.extantIDs(); // created and modified - difference.deleted().forEach(uncacheEntityID); // deleted + var entityIDs = difference.extantIDs(true); // created/modified (true = w/relation members) + difference.deleted().forEach(uncacheEntityID); // deleted validator.validateEntities(entityIDs); // dispatches 'validated' }; diff --git a/test/spec/core/difference.js b/test/spec/core/difference.js index 45ae6e04c..a5062e745 100644 --- a/test/spec/core/difference.js +++ b/test/spec/core/difference.js @@ -118,6 +118,36 @@ describe('iD.coreDifference', function () { var diff = iD.coreDifference(base, head); expect(diff.extantIDs()).to.eql([]); }); + + it('omits the ids of members of modified relations by default', function () { + var w1 = iD.osmWay({id: 'w1'}); + var w2 = iD.osmWay({id: 'w2'}); + var r1 = iD.osmRelation({ + id: 'r', + tags: { type: 'multipolygon' }, + members: [{role: 'outer', id: 'w1', type: 'way'}, {role: '', id: 'w2', type: 'way'}] + }); + var r2 = r1.update({ tags: { type: 'multipolygon', landuse: 'residential' }}); + var base = iD.coreGraph([r1, w1, w2]); + var head = base.replace(r2); + var diff = iD.coreDifference(base, head); + expect(diff.extantIDs()).to.eql(['r']); + }); + + it('includes the ids of members of modified relations with option', function () { + var w1 = iD.osmWay({id: 'w1'}); + var w2 = iD.osmWay({id: 'w2'}); + var r1 = iD.osmRelation({ + id: 'r', + tags: { type: 'multipolygon' }, + members: [{role: 'outer', id: 'w1', type: 'way'}, {role: '', id: 'w2', type: 'way'}] + }); + var r2 = r1.update({ tags: { type: 'multipolygon', landuse: 'residential' }}); + var base = iD.coreGraph([r1, w1, w2]); + var head = base.replace(r2); + var diff = iD.coreDifference(base, head); + expect(diff.extantIDs(true)).to.eql(['r', 'w1', 'w2']); + }); }); describe('#created', function () {