Rework presets.js file - WIP to fix resolving field inheritance

This commit is contained in:
Bryan Housel
2020-02-07 14:16:32 -05:00
parent 2003f7804b
commit 0357c2b80c
+97 -100
View File
@@ -8,101 +8,42 @@ import { utilSafeClassName } from '../util/util';
// `presetPreset` decorates a given `preset` Object
// with some extra methods for searching and matching geometry
//
export function presetPreset(presetID, preset, fields, addable, rawPresets) {
export function presetPreset(presetID, preset, allFields, addable, rawPresets) {
let _this = Object.assign({}, preset); // shallow copy
let _addable = addable || false;
_this.id = presetID;
// for use in classes, element ids, css selectors
_this.safeid = utilSafeClassName(presetID);
_this.safeid = utilSafeClassName(presetID); // for use in css classes, selectors, element ids
_this.parentPresetID = () => {
const endIndex = _this.id.lastIndexOf('/');
if (endIndex < 0) return null;
return _this.id.substring(0, endIndex);
};
_this.originalTerms = (_this.terms || []).join();
_this.originalName = _this.name || '';
// For a preset without fields, use the fields of the parent _this.
// Replace {preset} placeholders with the fields of the specified presets.
function resolveFieldInheritance() {
_this.originalScore = _this.matchScore || 1;
// Skip `fields` for the keys which define the _this.
// These are usually `typeCombo` fields like `shop=*`
function shouldInheritFieldWithID(fieldID) {
const f = fields[fieldID];
if (f.key) {
if (_this.tags[f.key] !== undefined &&
// inherit anyway if multiple values are allowed or just a checkbox
f.type !== 'multiCombo' && f.type !== 'semiCombo' && f.type !== 'check'
) return false;
}
return true;
}
_this.originalReference = _this.reference || {};
// returns an array of field IDs to inherit from the given presetID, if found
function inheritedFieldIDs(presetID, prop) {
if (!presetID) return null;
_this.fields = (_this.fields || []).map(f => allFields[f]);
const inheritPreset = rawPresets[presetID];
if (!inheritPreset) return null;
let inheritFieldIDs = inheritPreset[prop] || [];
if (prop === 'fields') {
inheritFieldIDs = inheritFieldIDs.filter(shouldInheritFieldWithID);
}
return inheritFieldIDs;
}
['fields', 'moreFields'].forEach(prop => {
let fieldIDs = [];
if (preset[prop] && preset[prop].length) { // fields were defined
preset[prop].forEach(fieldID => {
const match = fieldID.match(/\{(.*)\}/);
if (match !== null) { // presetID wrapped in braces {}
const inheritIDs = inheritedFieldIDs(match[1], prop);
if (inheritIDs !== null) {
fieldIDs = fieldIDs.concat(inheritIDs);
} else {
/* eslint-disable no-console */
console.log(`Cannot resolve presetID ${match[0]} found in ${_this.id} ${prop}`);
/* eslint-enable no-console */
}
} else {
fieldIDs.push(fieldID); // no braces - just a normal field
}
});
} else { // no fields defined, so use the parent's if possible
fieldIDs = inheritedFieldIDs(_this.parentPresetID(), prop);
}
fieldIDs = utilArrayUniq(fieldIDs);
preset[prop] = fieldIDs;
rawPresets[_this.id][prop] = fieldIDs;
});
}
_this.moreFields = (_this.moreFields || []).map(f => allFields[f]);
if (rawPresets) {
resolveFieldInheritance();
}
_this.fields = (_this.fields || []).map(getFields);
_this.moreFields = (_this.moreFields || []).map(getFields);
_this.tags = _this.tags || {};
_this.addTags = _this.addTags || _this.tags;
_this.removeTags = _this.removeTags || _this.addTags;
_this.geometry = (_this.geometry || []);
function getFields(f) {
return fields[f];
}
_this.matchGeometry = (geom) => _this.geometry.indexOf(geom) >= 0;
_this.matchAllGeometry = (geoms) => geoms.every(_this.matchGeometry);
_this.originalScore = _this.matchScore || 1;
_this.matchScore = (entityTags) => {
const tags = _this.tags;
let seen = {};
@@ -140,9 +81,6 @@ export function presetPreset(presetID, preset, fields, addable, rawPresets) {
};
_this.originalName = _this.name || '';
_this.name = () => {
if (_this.suggestion) {
let path = presetID.split('/');
@@ -154,27 +92,23 @@ export function presetPreset(presetID, preset, fields, addable, rawPresets) {
};
_this.originalTerms = (_this.terms || []).join();
_this.terms = () => _this.t('terms', { 'default': _this.originalTerms })
.toLowerCase().trim().split(/\s*,+\s*/);
_this.isFallback = () => {
const tagCount = Object.keys(_this.tags).length;
return tagCount === 0 || (tagCount === 1 && _this.tags.hasOwnProperty('area'));
};
addable = addable || false;
_this.addable = function(val) {
if (!arguments.length) return addable;
addable = val;
return addable;
if (!arguments.length) return _addable;
_addable = val;
return _this;
};
const _reference = _this.reference || {};
_this.reference = (geom) => {
// Lookup documentation on Wikidata...
const qid = _this.tags.wikidata || _this.tags['brand:wikidata'] || _this.tags['operator:wikidata'];
@@ -183,8 +117,8 @@ export function presetPreset(presetID, preset, fields, addable, rawPresets) {
}
// Lookup documentation on OSM Wikibase...
let key = _reference.key || Object.keys(utilObjectOmit(_this.tags, 'name'))[0];
let value = _reference.value || _this.tags[key];
let key = _this.originalReference.key || Object.keys(utilObjectOmit(_this.tags, 'name'))[0];
let value = _this.originalReference.value || _this.tags[key];
if (geom === 'relation' && key === 'type') {
if (value in _this.tags) {
@@ -203,16 +137,15 @@ export function presetPreset(presetID, preset, fields, addable, rawPresets) {
};
_this.removeTags = _this.removeTags || _this.addTags || _this.tags || {};
_this.unsetTags = (tags, geometry) => {
_this.unsetTags = (tags, geometry, skipFieldDefaults) => {
tags = utilObjectOmit(tags, Object.keys(_this.removeTags));
for (let f in _this.fields) {
const field = _this.fields[f];
if (field.matchGeometry(geometry) && field.default === tags[field.key]) {
delete tags[field.key];
}
if (geometry && !skipFieldDefaults) {
_this.fields.forEach(field => {
if (field.matchGeometry(geometry) && field.key && field.default === tags[field.key]) {
delete tags[field.key];
}
});
}
delete tags.area;
@@ -220,8 +153,6 @@ export function presetPreset(presetID, preset, fields, addable, rawPresets) {
};
_this.addTags = _this.addTags || _this.tags || {};
_this.setTags = (tags, geometry, skipFieldDefaults) => {
const addTags = _this.addTags;
tags = Object.assign({}, tags); // shallow copy
@@ -255,18 +186,84 @@ export function presetPreset(presetID, preset, fields, addable, rawPresets) {
}
}
}
if (geometry && !skipFieldDefaults) {
for (let f in _this.fields) {
const field = _this.fields[f];
_this.fields.forEach(field => {
if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
tags[field.key] = field.default;
}
}
});
}
return tags;
};
// For a preset without fields, use the fields of the parent preset.
// Replace {preset} placeholders with the fields of the specified presets.
function resolveFieldInheritance() {
['fields', 'moreFields'].forEach(prop => {
let fieldIDs = [];
if (preset[prop] && preset[prop].length) { // fields were defined
preset[prop].forEach(fieldID => {
const match = fieldID.match(/\{(.*)\}/);
if (match !== null) { // presetID wrapped in braces {}
const inheritIDs = inheritedFieldIDs(match[1], prop);
if (inheritIDs !== null) {
fieldIDs = fieldIDs.concat(inheritIDs);
} else {
/* eslint-disable no-console */
console.log(`Cannot resolve presetID ${match[0]} found in ${_this.id} ${prop}`);
/* eslint-enable no-console */
}
} else {
fieldIDs.push(fieldID); // no braces - just a normal field
}
});
} else { // no fields defined, so use the parent's if possible
const endIndex = _this.id.lastIndexOf('/');
const parentID = endIndex && _this.id.substring(0, endIndex);
if (parentID) {
fieldIDs = inheritedFieldIDs(parentID, prop);
}
}
fieldIDs = utilArrayUniq(fieldIDs);
preset[prop] = fieldIDs;
rawPresets[_this.id][prop] = fieldIDs;
});
// Skip `fields` for the keys which define the _this.
// These are usually `typeCombo` fields like `shop=*`
function shouldInheritFieldWithID(fieldID) {
const f = allFields[fieldID];
if (f.key) {
if (_this.tags[f.key] !== undefined &&
// inherit anyway if multiple values are allowed or just a checkbox
f.type !== 'multiCombo' && f.type !== 'semiCombo' && f.type !== 'check'
) return false;
}
return true;
}
// returns an array of field IDs to inherit from the given presetID, if found
function inheritedFieldIDs(presetID, prop) {
if (!presetID) return null;
const inheritPreset = rawPresets[presetID];
if (!inheritPreset) return null;
let inheritFieldIDs = inheritPreset[prop] || [];
if (prop === 'fields') {
inheritFieldIDs = inheritFieldIDs.filter(shouldInheritFieldWithID);
}
return inheritFieldIDs;
}
}
return _this;
}