<commit_before>import { filters } from 'name-suggestion-index';

import { t, languageName } from '../util/locale';
import { utilPreset } from '../util';
import { validationIssue, validationIssueFix } from '../core/validation';
import { actionChangeTags } from '../actions/change_tags';


export function validationSuspiciousName() {
    var type = 'suspicious_name';

    // known list of generic names (e.g. "bar")
    var discardNamesRegexes = filters.discardNames.map(function(discardName) {
        return new RegExp(discardName, 'i');
    });

    var keysToTestForGenericValues = ['amenity', 'building', 'leisure', 'man_made', 'shop', 'tourism'];

    function isDiscardedSuggestionName(lowercaseName) {
        for (var i = 0; i < discardNamesRegexes.length; i++) {
            if (discardNamesRegexes[i].test(lowercaseName)) {
                return true;
            }
        }
        return false;
    }

    // test if the name is just the key or tag value (e.g. "park")
    function nameMatchesRawTag(lowercaseName, tags) {
        var i, key, val;
        for (i = 0; i < keysToTestForGenericValues.length; i++) {
            key = keysToTestForGenericValues[i];
            val = tags[key];
            if (val) {
                val = val.toLowerCase();
                if (key === lowercaseName ||
                    val === lowercaseName ||
                    key.replace(/\_/g, ' ') === lowercaseName ||
                    val.replace(/\_/g, ' ') === lowercaseName) {
                    return true;
                }
            }
        }
        return false;
    }

    function isGenericName(name, tags) {
        name = name.toLowerCase();
        return nameMatchesRawTag(name, tags) || isDiscardedSuggestionName(name);
    }

    function makeGenericNameIssue(entityId, nameKey, genericName, langCode) {
        return new validationIssue({
            type: type,
            subtype: 'generic_name',
            severity: 'warning',
            message: function(context) {
                var entity = context.hasEntity(this.entityIds[0]);
                if (!entity) return '';
                var preset = utilPreset(entity, context);
                var langName = langCode && languageName(langCode);
                return t('issues.generic_name.message' + (langName ? '_language' : ''),
                    { feature: preset.name(), name: genericName, language: langName }
                );
            },
            reference: showReference,
            entityIds: [entityId],
            hash: nameKey + '=' + genericName,
            dynamicFixes: function() {
                return [
                    new validationIssueFix({
                        icon: 'iD-operation-delete',
                        title: t('issues.fix.remove_the_name.title'),
                        onClick: function(context) {
                            var entityId = this.issue.entityIds[0];
                            var entity = context.entity(entityId);
                            var tags = Object.assign({}, entity.tags);   // shallow copy
                            delete tags[nameKey];
                            context.perform(
                                actionChangeTags(entityId, tags),
                                t('issues.fix.remove_generic_name.annotation')
                            );
                        }
                    })
                ];
            }
        });

        function showReference(selection) {
            selection.selectAll('.issue-reference')
                .data([0])
                .enter()
                .append('div')
                .attr('class', 'issue-reference')
                .text(t('issues.generic_name.reference'));
        }
    }

    function makeIncorrectNameIssue(entityId, nameKey, incorrectName, langCode) {
        return new validationIssue({
            type: type,
            subtype: 'not_name',
            severity: 'warning',
            message: function(context) {
                var entity = context.hasEntity(this.entityIds[0]);
                if (!entity) return '';
                var preset = utilPreset(entity, context);
                var langName = langCode && languageName(langCode);
                return t('issues.incorrect_name.message' + (langName ? '_language' : ''),
                    { feature: preset.name(), name: incorrectName, language: langName }
                );
            },
            reference: showReference,
            entityIds: [entityId],
            hash: nameKey + '=' + incorrectName,
            dynamicFixes: function() {
                return [
                    new validationIssueFix({
                        icon: 'iD-operation-delete',
                        title: t('issues.fix.remove_the_name.title'),
                        onClick: function(context) {
                            var entityId = this.issue.entityIds[0];
                            var entity = context.entity(entityId);
                            var tags = Object.assign({}, entity.tags);   // shallow copy
                            delete tags[nameKey];
                            context.perform(
                                actionChangeTags(entityId, tags),
                                t('issues.fix.remove_mistaken_name.annotation')
                            );
                        }
                    })
                ];
            }
        });

        function showReference(selection) {
            selection.selectAll('.issue-reference')
                .data([0])
                .enter()
                .append('div')
                .attr('class', 'issue-reference')
                .text(t('issues.generic_name.reference'));
        }
    }


    var validation = function checkGenericName(entity) {
        // a generic name is okay if it's a known brand or entity
        if (entity.hasWikidata()) return [];

        var issues = [];

        var notNames = (entity.tags['not:name'] || '').split(';');

        for (var key in entity.tags) {
            var m = key.match(/^name(?:(?::)([a-zA-Z_-]+))?$/);
            if (!m) continue;

            var langCode = m.length >= 2 ? m[1] : null;

            var value = entity.tags[key];
            if (notNames.length) {
                for (var i in notNames) {
                    var notName = notNames[i];
                    if (value === notName) {
                        issues.push(makeIncorrectNameIssue(entity.id, key, value, langCode));
                        continue;
                    }
                }
            }
            if (isGenericName(value, entity.tags)) {
                issues.push(makeGenericNameIssue(entity.id, key, value, langCode));
            }
        }

        return issues;<commit_msg>Don't flag empty `name` tag as mistaken (close #7153)<commit_after>import { filters } from 'name-suggestion-index';

import { t, languageName } from '../util/locale';
import { utilPreset } from '../util';
import { validationIssue, validationIssueFix } from '../core/validation';
import { actionChangeTags } from '../actions/change_tags';


export function validationSuspiciousName() {
    var type = 'suspicious_name';

    // known list of generic names (e.g. "bar")
    var discardNamesRegexes = filters.discardNames.map(function(discardName) {
        return new RegExp(discardName, 'i');
    });

    var keysToTestForGenericValues = ['amenity', 'building', 'leisure', 'man_made', 'shop', 'tourism'];

    function isDiscardedSuggestionName(lowercaseName) {
        for (var i = 0; i < discardNamesRegexes.length; i++) {
            if (discardNamesRegexes[i].test(lowercaseName)) {
                return true;
            }
        }
        return false;
    }

    // test if the name is just the key or tag value (e.g. "park")
    function nameMatchesRawTag(lowercaseName, tags) {
        var i, key, val;
        for (i = 0; i < keysToTestForGenericValues.length; i++) {
            key = keysToTestForGenericValues[i];
            val = tags[key];
            if (val) {
                val = val.toLowerCase();
                if (key === lowercaseName ||
                    val === lowercaseName ||
                    key.replace(/\_/g, ' ') === lowercaseName ||
                    val.replace(/\_/g, ' ') === lowercaseName) {
                    return true;
                }
            }
        }
        return false;
    }

    function isGenericName(name, tags) {
        name = name.toLowerCase();
        return nameMatchesRawTag(name, tags) || isDiscardedSuggestionName(name);
    }

    function makeGenericNameIssue(entityId, nameKey, genericName, langCode) {
        return new validationIssue({
            type: type,
            subtype: 'generic_name',
            severity: 'warning',
            message: function(context) {
                var entity = context.hasEntity(this.entityIds[0]);
                if (!entity) return '';
                var preset = utilPreset(entity, context);
                var langName = langCode && languageName(langCode);
                return t('issues.generic_name.message' + (langName ? '_language' : ''),
                    { feature: preset.name(), name: genericName, language: langName }
                );
            },
            reference: showReference,
            entityIds: [entityId],
            hash: nameKey + '=' + genericName,
            dynamicFixes: function() {
                return [
                    new validationIssueFix({
                        icon: 'iD-operation-delete',
                        title: t('issues.fix.remove_the_name.title'),
                        onClick: function(context) {
                            var entityId = this.issue.entityIds[0];
                            var entity = context.entity(entityId);
                            var tags = Object.assign({}, entity.tags);   // shallow copy
                            delete tags[nameKey];
                            context.perform(
                                actionChangeTags(entityId, tags),
                                t('issues.fix.remove_generic_name.annotation')
                            );
                        }
                    })
                ];
            }
        });

        function showReference(selection) {
            selection.selectAll('.issue-reference')
                .data([0])
                .enter()
                .append('div')
                .attr('class', 'issue-reference')
                .text(t('issues.generic_name.reference'));
        }
    }

    function makeIncorrectNameIssue(entityId, nameKey, incorrectName, langCode) {
        return new validationIssue({
            type: type,
            subtype: 'not_name',
            severity: 'warning',
            message: function(context) {
                var entity = context.hasEntity(this.entityIds[0]);
                if (!entity) return '';
                var preset = utilPreset(entity, context);
                var langName = langCode && languageName(langCode);
                return t('issues.incorrect_name.message' + (langName ? '_language' : ''),
                    { feature: preset.name(), name: incorrectName, language: langName }
                );
            },
            reference: showReference,
            entityIds: [entityId],
            hash: nameKey + '=' + incorrectName,
            dynamicFixes: function() {
                return [
                    new validationIssueFix({
                        icon: 'iD-operation-delete',
                        title: t('issues.fix.remove_the_name.title'),
                        onClick: function(context) {
                            var entityId = this.issue.entityIds[0];
                            var entity = context.entity(entityId);
                            var tags = Object.assign({}, entity.tags);   // shallow copy
                            delete tags[nameKey];
                            context.perform(
                                actionChangeTags(entityId, tags),
                                t('issues.fix.remove_mistaken_name.annotation')
                            );
                        }
                    })
                ];
            }
        });

        function showReference(selection) {
            selection.selectAll('.issue-reference')
                .data([0])
                .enter()
                .append('div')
                .attr('class', 'issue-reference')
                .text(t('issues.generic_name.reference'));
        }
    }


    var validation = function checkGenericName(entity) {
        // a generic name is okay if it's a known brand or entity
        if (entity.hasWikidata()) return [];

        var issues = [];

        var notNames = (entity.tags['not:name'] || '').split(';');

        for (var key in entity.tags) {
            var m = key.match(/^name(?:(?::)([a-zA-Z_-]+))?$/);
            if (!m) continue;

            var langCode = m.length >= 2 ? m[1] : null;

            var value = entity.tags[key];
            if (notNames.length) {
                for (var i in notNames) {
                    var notName = notNames[i];
                    if (notName && value === notName) {
                        issues.push(makeIncorrectNameIssue(entity.id, key, value, langCode));
                        continue;
                    }
                }
            }
            if (isGenericName(value, entity.tags)) {
                issues.push(makeGenericNameIssue(entity.id, key, value, langCode));
            }
        }

        return issues;
{'fraction_non_alphanumeric': 0.11561881006529234, 'fraction_numerical': 0.0017606925390653658, 'mean_word_length': 1.3869725091927858, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7542960', 'n_tokens_mistral': 3522, 'n_tokens_neox': 3310, 'n_words': 734}