function oldTagIssues()

in modules/validations/outdated_tags.js [32:225]


    function oldTagIssues(entity, graph) {
        var oldTags = Object.assign({}, entity.tags);  // shallow copy
        var preset = context.presets().match(entity, graph);
        var explicitPresetUpgrade = preset.replacement;
        var subtype = 'deprecated_tags';

        // upgrade preset..
        if (preset.replacement) {
            var newPreset = context.presets().item(preset.replacement);
            graph = actionChangePreset(entity.id, preset, newPreset)(graph);
            entity = graph.entity(entity.id);
            preset = newPreset;
        }

        // upgrade tags..
        var deprecatedTags = entity.deprecatedTags();
        if (deprecatedTags.length) {
            deprecatedTags.forEach(function(tag) {
                graph = actionUpgradeTags(entity.id, tag.old, tag.replace)(graph);
            });
            entity = graph.entity(entity.id);
        }

        // add missing addTags..
        var newTags = Object.assign({}, entity.tags);  // shallow copy
        if (preset.tags !== preset.addTags) {
            Object.keys(preset.addTags).forEach(function(k) {
                if (!newTags[k]) {
                    newTags[k] = preset.addTags[k];
                    if (!explicitPresetUpgrade) {
                        subtype = 'incomplete_tags';
                    }
                }
            });
        }

        // Do `wikidata` or `wikipedia` identify this entity as a brand?  #6416
        // If so, these tags can be swapped to `brand:wikidata`/`brand:wikipedia`
        var isBrand;
        if (newTags.wikidata) {                 // try matching `wikidata`
            isBrand = allWD[newTags.wikidata];
        }
        if (!isBrand && newTags.wikipedia) {    // fallback to `wikipedia`
            isBrand = allWP[newTags.wikipedia];
        }
        if (isBrand && !newTags.office) {       // but avoid doing this for corporate offices
            if (newTags.wikidata) {
                newTags['brand:wikidata'] = newTags.wikidata;
                delete newTags.wikidata;
            }
            if (newTags.wikipedia) {
                newTags['brand:wikipedia'] = newTags.wikipedia;
                delete newTags.wikipedia;
            }
            // I considered setting `name` and other tags here, but they aren't unique per wikidata
            // (Q2759586 -> in USA "Papa John's", in Russia "Папа Джонс")
            // So users will really need to use a preset or assign `name` themselves.
        }

        // try key/value|name match against name-suggestion-index
        if (newTags.name) {
            for (var i = 0; i < nsiKeys.length; i++) {
                var k = nsiKeys[i];
                if (!newTags[k]) continue;

                var center = entity.extent(graph).center();
                var countryCode = countryCoder.iso1A2Code(center);
                var match = nsiMatcher.matchKVN(k, newTags[k], newTags.name, countryCode && countryCode.toLowerCase());
                if (!match) continue;

                // for now skip ambiguous matches (like Target~(USA) vs Target~(Australia))
                if (match.d) continue;

                var brand = brands.brands[match.kvnd];
                if (brand && brand.tags['brand:wikidata'] &&
                    brand.tags['brand:wikidata'] !== entity.tags['not:brand:wikidata']) {
                    subtype = 'noncanonical_brand';

                    var keepTags = ['takeaway'].reduce(function(acc, k) {
                        if (newTags[k]) {
                            acc[k] = newTags[k];
                        }
                        return acc;
                    }, {});

                    nsiKeys.forEach(function(k) { delete newTags[k]; });
                    Object.assign(newTags, brand.tags, keepTags);
                    break;
                }
            }
        }


        // determine diff
        var tagDiff = utilTagDiff(oldTags, newTags);
        if (!tagDiff.length) return [];

        var prefix = '';
        if (subtype === 'noncanonical_brand') {
            prefix = 'noncanonical_brand.';
        } else if (subtype === 'incomplete_tags') {
            prefix = 'incomplete.';
        }

        // don't allow autofixing brand tags
        var autoArgs = subtype !== 'noncanonical_brand' ? [doUpgrade, t('issues.fix.upgrade_tags.annotation')] : null;

        return [new validationIssue({
            type: type,
            subtype: subtype,
            severity: 'warning',
            message: showMessage,
            reference: showReference,
            entityIds: [entity.id],
            hash: JSON.stringify(tagDiff),
            dynamicFixes: function() {
                return [
                    new validationIssueFix({
                        autoArgs: autoArgs,
                        title: t('issues.fix.upgrade_tags.title'),
                        onClick: function(context) {
                            context.perform(doUpgrade, t('issues.fix.upgrade_tags.annotation'));
                        }
                    })
                ];
            }
        })];


        function doUpgrade(graph) {
            var currEntity = graph.hasEntity(entity.id);
            if (!currEntity) return graph;

            var newTags = Object.assign({}, currEntity.tags);  // shallow copy
            tagDiff.forEach(function(diff) {
                if (diff.type === '-') {
                    delete newTags[diff.key];
                } else if (diff.type === '+') {
                    newTags[diff.key] = diff.newVal;
                }
            });

            return actionChangeTags(currEntity.id, newTags)(graph);
        }


        function showMessage(context) {
            var currEntity = context.hasEntity(entity.id);
            if (!currEntity) return '';

            var messageID = 'issues.outdated_tags.' + prefix + 'message';

            if (subtype === 'noncanonical_brand' && tagDiff.every(function(d) {
                return d.type === '+';
            })) {
                messageID += '_incomplete';
            }

            return t(messageID,
                { feature: utilDisplayLabel(currEntity, context) }
            );
        }


        function showReference(selection) {
            var enter = selection.selectAll('.issue-reference')
                .data([0])
                .enter();

            enter
                .append('div')
                .attr('class', 'issue-reference')
                .text(t('issues.outdated_tags.' + prefix + 'reference'));

            enter
                .append('strong')
                .text(t('issues.suggested'));

            enter
                .append('table')
                .attr('class', 'tagDiff-table')
                .selectAll('.tagDiff-row')
                .data(tagDiff)
                .enter()
                .append('tr')
                .attr('class', 'tagDiff-row')
                .append('td')
                .attr('class', function(d) {
                    var klass = d.type === '+' ? 'add' : 'remove';
                    return 'tagDiff-cell tagDiff-cell-' + klass;
                })
                .text(function(d) { return d.display; });
        }
    }