Don't bundle the nsi brands anymore, fetch from CDN at runtime

(re: #4994)
This commit is contained in:
Bryan Housel
2020-02-01 17:40:56 -05:00
parent 743dc0a83a
commit 06eac7c9d0
4 changed files with 165 additions and 166 deletions
+1 -1
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -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',
+161 -164
View File
@@ -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;
}
+2 -1
View File
@@ -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({