diff --git a/modules/actions/index.js b/modules/actions/index.js
index acb76f3ff..6eac6bfc6 100644
--- a/modules/actions/index.js
+++ b/modules/actions/index.js
@@ -33,3 +33,4 @@ export { actionStraighten } from './straighten';
export { actionUnrestrictTurn } from './unrestrict_turn';
export { actionReflect } from './reflect.js';
export { actionDetachNode } from './detach_node';
+export { actionUpgradeTags } from './upgrade_tags';
diff --git a/modules/actions/upgrade_tags.js b/modules/actions/upgrade_tags.js
new file mode 100644
index 000000000..38ca76675
--- /dev/null
+++ b/modules/actions/upgrade_tags.js
@@ -0,0 +1,35 @@
+import _clone from 'lodash-es/clone';
+
+export function actionUpgradeTags(entityId, oldTags, replaceTags) {
+ return function(graph) {
+ var entity = graph.entity(entityId);
+ var tags = _clone(entity.tags);
+ var transferValue;
+ for (var oldTagKey in oldTags) {
+ if (oldTags[oldTagKey] === '*') {
+ transferValue = tags[oldTagKey];
+ }
+ delete tags[oldTagKey];
+ }
+ if (replaceTags) {
+ for (var replaceKey in replaceTags) {
+ var replaceValue = replaceTags[replaceKey];
+ if (replaceValue === '*') {
+ if (tags[replaceKey]) {
+ // any value is okay and there already
+ // is one, so don't update it
+ continue;
+ } else {
+ // otherwise assume `yes` is okay
+ tags[replaceKey] = 'yes';
+ }
+ } else if (replaceValue === '$1') {
+ tags[replaceKey] = transferValue;
+ } else {
+ tags[replaceKey] = replaceValue;
+ }
+ }
+ }
+ return graph.replace(entity.update({tags: tags}));
+ };
+}
diff --git a/modules/validations/deprecated_tag.js b/modules/validations/deprecated_tag.js
index e72677814..56dba449d 100644
--- a/modules/validations/deprecated_tag.js
+++ b/modules/validations/deprecated_tag.js
@@ -1,7 +1,7 @@
import _clone from 'lodash-es/clone';
import { t } from '../util/locale';
-import { actionChangeTags } from '../actions';
+import { actionUpgradeTags, actionChangeTags } from '../actions';
import { utilDisplayLabel, utilTagText } from '../util';
import { validationIssue, validationIssueFix } from '../core/validator';
@@ -48,37 +48,11 @@ export function validationDeprecatedTag() {
icon: 'iD-icon-up',
title: t('issues.fix.' + (isCombo ? 'upgrade_tag_combo' : 'upgrade_tag') + '.title'),
onClick: function() {
- var entity = this.issue.entities[0];
- var tags = _clone(entity.tags);
- var replaceTags = this.issue.info.replaceTags;
var oldTags = this.issue.info.oldTags;
+ var replaceTags = this.issue.info.replaceTags;
var fixTextID = Object.keys(oldTags).length > 1 ? 'upgrade_tag_combo' : 'upgrade_tag';
- var transferValue;
- for (var oldTagKey in oldTags) {
- if (oldTags[oldTagKey] === '*') {
- transferValue = tags[oldTagKey];
- }
- delete tags[oldTagKey];
- }
- for (var replaceKey in replaceTags) {
- var replaceValue = replaceTags[replaceKey];
- if (replaceValue === '*') {
- if (tags[replaceKey]) {
- // any value is okay and there already
- // is one, so don't update it
- continue;
- } else {
- // otherwise assume `yes` is okay
- tags[replaceKey] = 'yes';
- }
- } else if (replaceValue === '$1') {
- tags[replaceKey] = transferValue;
- } else {
- tags[replaceKey] = replaceValue;
- }
- }
context.perform(
- actionChangeTags(entity.id, tags),
+ actionUpgradeTags(this.issue.entities[0].id, oldTags, replaceTags),
t('issues.fix.' + fixTextID + '.annotation')
);
}
diff --git a/test/index.html b/test/index.html
index 66bf09be9..8ac0e0974 100644
--- a/test/index.html
+++ b/test/index.html
@@ -63,6 +63,7 @@
+
diff --git a/test/spec/actions/upgrade_tags.js b/test/spec/actions/upgrade_tags.js
new file mode 100644
index 000000000..eba80416d
--- /dev/null
+++ b/test/spec/actions/upgrade_tags.js
@@ -0,0 +1,59 @@
+describe('iD.actionUpgradeTags', function () {
+
+ it('upgrades a tag', function () {
+ var oldTags = { amenity: 'swimming_pool' },
+ newTags = { leisure: 'swimming_pool' },
+ entity = iD.Entity({ tags: { amenity: 'swimming_pool', name: 'Foo' }}),
+ graph = iD.actionUpgradeTags(entity.id, oldTags, newTags)(iD.coreGraph([entity]));
+ expect(graph.entity(entity.id).tags).to.eql({ leisure: 'swimming_pool', name: 'Foo' });
+ });
+
+ it('upgrades a tag combination', function () {
+ var oldTags = { amenity: 'vending_machine', vending: 'news_papers' },
+ newTags = { amenity: 'vending_machine', vending: 'newspapers' },
+ entity = iD.Entity({ tags: { amenity: 'vending_machine', vending: 'news_papers', name: 'Foo' }}),
+ graph = iD.actionUpgradeTags(entity.id, oldTags, newTags)(iD.coreGraph([entity]));
+ expect(graph.entity(entity.id).tags).to.eql({ amenity: 'vending_machine', vending: 'newspapers', name: 'Foo' });
+ });
+
+ it('upgrades a tag with multiple replacement tags', function () {
+ var oldTags = { natural: 'marsh' },
+ newTags = { natural: 'wetland', wetland: 'marsh' },
+ entity = iD.Entity({ tags: { natural: 'marsh', name: 'Foo' }}),
+ graph = iD.actionUpgradeTags(entity.id, oldTags, newTags)(iD.coreGraph([entity]));
+ expect(graph.entity(entity.id).tags).to.eql({ natural: 'wetland', wetland: 'marsh', name: 'Foo' });
+ });
+
+ it('upgrades a tag with no replacement tags', function () {
+ var oldTags = { highway: 'no' },
+ newTags = undefined,
+ entity = iD.Entity({ tags: { highway: 'no', name: 'Foo' }}),
+ graph = iD.actionUpgradeTags(entity.id, oldTags, newTags)(iD.coreGraph([entity]));
+ expect(graph.entity(entity.id).tags).to.eql({ name: 'Foo' });
+ });
+
+ it('upgrades a wildcard tag and moves the value', function () {
+ var oldTags = { color: '*' },
+ newTags = { colour: '$1' },
+ entity = iD.Entity({ tags: { color: 'red', name: 'Foo' }}),
+ graph = iD.actionUpgradeTags(entity.id, oldTags, newTags)(iD.coreGraph([entity]));
+ expect(graph.entity(entity.id).tags).to.eql({ colour: 'red', name: 'Foo' });
+ });
+
+ it('upgrades a tag with a wildcard replacement and adds a default value', function () {
+ var oldTags = { amenity: 'shop' },
+ newTags = { shop: '*' },
+ entity = iD.Entity({ tags: { amenity: 'shop', name: 'Foo' }}),
+ graph = iD.actionUpgradeTags(entity.id, oldTags, newTags)(iD.coreGraph([entity]));
+ expect(graph.entity(entity.id).tags).to.eql({ shop: 'yes', name: 'Foo' });
+ });
+
+ it('upgrades a tag with a wildcard replacement and maintains the existing value', function () {
+ var oldTags = { amenity: 'shop' },
+ newTags = { shop: '*' },
+ entity = iD.Entity({ tags: { amenity: 'shop', shop: 'supermarket', name: 'Foo' }}),
+ graph = iD.actionUpgradeTags(entity.id, oldTags, newTags)(iD.coreGraph([entity]));
+ expect(graph.entity(entity.id).tags).to.eql({ shop: 'supermarket', name: 'Foo' });
+ });
+
+});