mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-24 00:54:03 +02:00
Don't bundle the nsi brands anymore, fetch from CDN at runtime
(re: #4994)
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -17,6 +17,7 @@ export function coreData(context) {
|
||||
'languages': 'data/languages.min.json',
|
||||
'locales': 'data/locales.min.json',
|
||||
'nsi_brands': 'https://cdn.jsdelivr.net/npm/name-suggestion-index@3/dist/brands.min.json',
|
||||
'nsi_filters': 'https://cdn.jsdelivr.net/npm/name-suggestion-index@3/dist/filters.min.json',
|
||||
'oci_features': 'https://cdn.jsdelivr.net/npm/osm-community-index@2/dist/features.min.json',
|
||||
'oci_resources': 'https://cdn.jsdelivr.net/npm/osm-community-index@2/dist/resources.min.json',
|
||||
'phone_formats': 'data/phone_formats.min.json',
|
||||
|
||||
@@ -1,182 +1,179 @@
|
||||
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';
|
||||
let _discardNameRegexes = [];
|
||||
|
||||
// known list of generic names (e.g. "bar")
|
||||
var discardNamesRegexes = filters.discardNames.map(function(discardName) {
|
||||
return new RegExp(discardName, 'i');
|
||||
export function validationSuspiciousName(context) {
|
||||
const type = 'suspicious_name';
|
||||
const keysToTestForGenericValues = ['amenity', 'building', 'leisure', 'man_made', 'shop', 'tourism'];
|
||||
|
||||
// A concern here in switching to async data means that `_nsiFilters` will not
|
||||
// be available at first, so the data on early tiles may not have tags validated fully.
|
||||
|
||||
context.data().get('nsi_filters')
|
||||
.then(filters => {
|
||||
// known list of generic names (e.g. "bar")
|
||||
_discardNameRegexes = filters.discardNames
|
||||
.map(discardName => new RegExp(discardName, 'i'));
|
||||
})
|
||||
.catch(() => { /* ignore */ });
|
||||
|
||||
|
||||
function isDiscardedSuggestionName(lowercaseName) {
|
||||
return _discardNameRegexes.some(regex => regex.test(lowercaseName));
|
||||
}
|
||||
|
||||
// test if the name is just the key or tag value (e.g. "park")
|
||||
function nameMatchesRawTag(lowercaseName, tags) {
|
||||
for (let i = 0; i < keysToTestForGenericValues.length; i++) {
|
||||
let key = keysToTestForGenericValues[i];
|
||||
let 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) {
|
||||
let entity = context.hasEntity(this.entityIds[0]);
|
||||
if (!entity) return '';
|
||||
let preset = utilPreset(entity, context);
|
||||
let langName = langCode && languageName(context, 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) {
|
||||
let entityId = this.issue.entityIds[0];
|
||||
let entity = context.entity(entityId);
|
||||
let tags = Object.assign({}, entity.tags); // shallow copy
|
||||
delete tags[nameKey];
|
||||
context.perform(
|
||||
actionChangeTags(entityId, tags), t('issues.fix.remove_generic_name.annotation')
|
||||
);
|
||||
}
|
||||
})
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
var keysToTestForGenericValues = ['amenity', 'building', 'leisure', 'man_made', 'shop', 'tourism'];
|
||||
function showReference(selection) {
|
||||
selection.selectAll('.issue-reference')
|
||||
.data([0])
|
||||
.enter()
|
||||
.append('div')
|
||||
.attr('class', 'issue-reference')
|
||||
.text(t('issues.generic_name.reference'));
|
||||
}
|
||||
}
|
||||
|
||||
function isDiscardedSuggestionName(lowercaseName) {
|
||||
for (var i = 0; i < discardNamesRegexes.length; i++) {
|
||||
if (discardNamesRegexes[i].test(lowercaseName)) {
|
||||
return true;
|
||||
function makeIncorrectNameIssue(entityId, nameKey, incorrectName, langCode) {
|
||||
return new validationIssue({
|
||||
type: type,
|
||||
subtype: 'not_name',
|
||||
severity: 'warning',
|
||||
message: function(context) {
|
||||
const entity = context.hasEntity(this.entityIds[0]);
|
||||
if (!entity) return '';
|
||||
const preset = utilPreset(entity, context);
|
||||
const langName = langCode && languageName(context, 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) {
|
||||
const entityId = this.issue.entityIds[0];
|
||||
const entity = context.entity(entityId);
|
||||
let 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'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let validation = function checkGenericName(entity) {
|
||||
// a generic name is okay if it's a known brand or entity
|
||||
if (entity.hasWikidata()) return [];
|
||||
|
||||
let issues = [];
|
||||
const notNames = (entity.tags['not:name'] || '').split(';');
|
||||
|
||||
for (let key in entity.tags) {
|
||||
const m = key.match(/^name(?:(?::)([a-zA-Z_-]+))?$/);
|
||||
if (!m) continue;
|
||||
|
||||
const langCode = m.length >= 2 ? m[1] : null;
|
||||
const value = entity.tags[key];
|
||||
if (notNames.length) {
|
||||
for (let i in notNames) {
|
||||
const notName = notNames[i];
|
||||
if (notName && value === notName) {
|
||||
issues.push(makeIncorrectNameIssue(entity.id, key, value, langCode));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (isGenericName(value, entity.tags)) {
|
||||
issues.push(makeGenericNameIssue(entity.id, key, value, langCode));
|
||||
}
|
||||
}
|
||||
|
||||
// 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(context, 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(context, 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'));
|
||||
}
|
||||
}
|
||||
return issues;
|
||||
};
|
||||
|
||||
|
||||
var validation = function checkGenericName(entity) {
|
||||
// a generic name is okay if it's a known brand or entity
|
||||
if (entity.hasWikidata()) return [];
|
||||
validation.type = type;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
validation.type = type;
|
||||
|
||||
return validation;
|
||||
return validation;
|
||||
}
|
||||
|
||||
@@ -20,9 +20,10 @@ iD.data.presets = {
|
||||
}
|
||||
};
|
||||
|
||||
// creating `coreContext` creates validators, and `validatonOutdatedTags` will try to load these
|
||||
// creating `coreContext` creates validators and some of the validators try loading these
|
||||
iD.data.deprecated = [];
|
||||
iD.data.nsi_brands = [];
|
||||
iD.data.nsi_filters = [];
|
||||
|
||||
|
||||
mocha.setup({
|
||||
|
||||
Reference in New Issue
Block a user