move deprecatedTags logic out of osmEntity and into a helper function (#10842)

This commit is contained in:
Kyℓe Hensel
2025-03-08 04:29:25 +11:00
committed by GitHub
parent 16f1187c04
commit 9d16588f19
6 changed files with 183 additions and 132 deletions
+81
View File
@@ -0,0 +1,81 @@
/** @typedef {{ old: Tags; replace?: Tags }[]} DataDeprecated */
/** @param {Tags} tags @param {DataDeprecated} dataDeprecated */
export function getDeprecatedTags(tags, dataDeprecated) {
// if there are no tags, none can be deprecated
if (Object.keys(tags).length === 0) return [];
/** @type {DataDeprecated} */
var deprecated = [];
dataDeprecated.forEach((d) => {
var oldKeys = Object.keys(d.old);
if (d.replace) {
var hasExistingValues = Object.keys(d.replace).some((replaceKey) => {
if (!tags[replaceKey] || d.old[replaceKey]) return false;
var replaceValue = d.replace[replaceKey];
if (replaceValue === '*') return false;
if (replaceValue === tags[replaceKey]) return false;
return true;
});
// don't flag deprecated tags if the upgrade path would overwrite existing data - #7843
if (hasExistingValues) return;
}
var matchesDeprecatedTags = oldKeys.every((oldKey) => {
if (!tags[oldKey]) return false;
if (d.old[oldKey] === '*') return true;
if (d.old[oldKey] === tags[oldKey]) return true;
var vals = tags[oldKey].split(';').filter(Boolean);
if (vals.length === 0) {
return false;
} else if (vals.length > 1) {
return vals.indexOf(d.old[oldKey]) !== -1;
} else {
if (tags[oldKey] === d.old[oldKey]) {
if (d.replace && d.old[oldKey] === d.replace[oldKey]) {
var replaceKeys = Object.keys(d.replace);
return !replaceKeys.every((replaceKey) => {
return tags[replaceKey] === d.replace[replaceKey];
});
} else {
return true;
}
}
}
return false;
});
if (matchesDeprecatedTags) {
deprecated.push(d);
}
});
return deprecated;
}
/** @type {{ [key: string]: string[] }} */
var _deprecatedTagValuesByKey;
/** @param {DataDeprecated} dataDeprecated */
export function deprecatedTagValuesByKey(dataDeprecated) {
if (!_deprecatedTagValuesByKey) {
_deprecatedTagValuesByKey = {};
dataDeprecated.forEach((d) => {
var oldKeys = Object.keys(d.old);
if (oldKeys.length === 1) {
var oldKey = oldKeys[0];
var oldValue = d.old[oldKey];
if (oldValue !== '*') {
if (!_deprecatedTagValuesByKey[oldKey]) {
_deprecatedTagValuesByKey[oldKey] = [oldValue];
} else {
_deprecatedTagValuesByKey[oldKey].push(oldValue);
}
}
}
});
}
return _deprecatedTagValuesByKey;
};
-75
View File
@@ -54,29 +54,6 @@ osmEntity.key = function(entity) {
return entity.id + 'v' + (entity.v || 0);
};
var _deprecatedTagValuesByKey;
osmEntity.deprecatedTagValuesByKey = function(dataDeprecated) {
if (!_deprecatedTagValuesByKey) {
_deprecatedTagValuesByKey = {};
dataDeprecated.forEach(function(d) {
var oldKeys = Object.keys(d.old);
if (oldKeys.length === 1) {
var oldKey = oldKeys[0];
var oldValue = d.old[oldKey];
if (oldValue !== '*') {
if (!_deprecatedTagValuesByKey[oldKey]) {
_deprecatedTagValuesByKey[oldKey] = [oldValue];
} else {
_deprecatedTagValuesByKey[oldKey].push(oldValue);
}
}
}
});
}
return _deprecatedTagValuesByKey;
};
osmEntity.prototype = {
@@ -185,56 +162,4 @@ osmEntity.prototype = {
isDegenerate: function() {
return true;
},
deprecatedTags: function(dataDeprecated) {
var tags = this.tags;
// if there are no tags, none can be deprecated
if (Object.keys(tags).length === 0) return [];
var deprecated = [];
dataDeprecated.forEach(function(d) {
var oldKeys = Object.keys(d.old);
if (d.replace) {
var hasExistingValues = Object.keys(d.replace).some(function(replaceKey) {
if (!tags[replaceKey] || d.old[replaceKey]) return false;
var replaceValue = d.replace[replaceKey];
if (replaceValue === '*') return false;
if (replaceValue === tags[replaceKey]) return false;
return true;
});
// don't flag deprecated tags if the upgrade path would overwrite existing data - #7843
if (hasExistingValues) return;
}
var matchesDeprecatedTags = oldKeys.every(function(oldKey) {
if (!tags[oldKey]) return false;
if (d.old[oldKey] === '*') return true;
if (d.old[oldKey] === tags[oldKey]) return true;
var vals = tags[oldKey].split(';').filter(Boolean);
if (vals.length === 0) {
return false;
} else if (vals.length > 1) {
return vals.indexOf(d.old[oldKey]) !== -1;
} else {
if (tags[oldKey] === d.old[oldKey]) {
if (d.replace && d.old[oldKey] === d.replace[oldKey]) {
var replaceKeys = Object.keys(d.replace);
return !replaceKeys.every(function(replaceKey) {
return tags[replaceKey] === d.replace[replaceKey];
});
} else {
return true;
}
}
}
return false;
});
if (matchesDeprecatedTags) {
deprecated.push(d);
}
});
return deprecated;
}
};
+2 -2
View File
@@ -4,7 +4,6 @@ import { drag as d3_drag } from 'd3-drag';
import * as countryCoder from '@rapideditor/country-coder';
import { fileFetcher } from '../../core/file_fetcher';
import { osmEntity } from '../../osm/entity';
import { t } from '../../core/localizer';
import { services } from '../../services';
import { uiCombobox } from '../combobox';
@@ -13,6 +12,7 @@ import { svgIcon } from '../../svg/icon';
import { utilKeybinding } from '../../util/keybinding';
import { utilArrayUniq, utilGetSetValue, utilNoAuto, utilRebind, utilTotalExtent, utilUnicodeCharsCount } from '../../util';
import { uiLengthIndicator } from '../length_indicator';
import { deprecatedTagValuesByKey } from '../../osm/deprecated';
export {
uiFieldCombo as uiFieldManyCombo,
@@ -258,7 +258,7 @@ export function uiFieldCombo(field, context) {
return value === restrictTagValueSpelling(value);
});
var deprecatedValues = osmEntity.deprecatedTagValuesByKey(_dataDeprecated)[field.key];
var deprecatedValues = deprecatedTagValuesByKey(_dataDeprecated)[field.key];
if (deprecatedValues) {
// don't suggest deprecated tag values
data = data.filter(d =>
+2 -1
View File
@@ -9,6 +9,7 @@ import { services } from '../services';
import { utilHashcode, utilTagDiff } from '../util';
import { utilDisplayLabel } from '../util/utilDisplayLabel';
import { validationIssue, validationIssueFix } from '../core/validation';
import { getDeprecatedTags } from '../osm/deprecated';
/** @import { TagDiff } from '../util/util'. */
@@ -43,7 +44,7 @@ export function validationOutdatedTags() {
// Upgrade deprecated tags..
if (_dataDeprecated) {
const deprecatedTags = entity.deprecatedTags(_dataDeprecated);
const deprecatedTags = getDeprecatedTags(entity.tags, _dataDeprecated);
if (entity.type === 'way' && entity.isClosed() &&
entity.tags.traffic_calming === 'island' && !entity.tags.highway) {
// https://github.com/openstreetmap/id-tagging-schema/issues/1162#issuecomment-2000356902
+98
View File
@@ -0,0 +1,98 @@
import {
deprecatedTagValuesByKey,
getDeprecatedTags,
type DataDeprecated,
} from '../../../modules/osm/deprecated';
var deprecated: DataDeprecated = [
{ old: { highway: 'no' } },
{ old: { amenity: 'toilet' }, replace: { amenity: 'toilets' } },
{ old: { speedlimit: '*' }, replace: { maxspeed: '$1' } },
{
old: { man_made: 'water_tank' },
replace: { man_made: 'storage_tank', content: 'water' },
},
{
old: { amenity: 'gambling', gambling: 'casino' },
replace: { amenity: 'casino' },
},
];
describe('getDeprecatedTags', () => {
it('returns none if entity has no tags', () => {
expect(getDeprecatedTags({}, deprecated)).toStrictEqual([]);
});
it('returns none when no tags are deprecated', () => {
expect(getDeprecatedTags({ amenity: 'toilets' }, deprecated)).toStrictEqual(
[],
);
});
it('returns 1:0 replacement', () => {
expect(getDeprecatedTags({ highway: 'no' }, deprecated)).toStrictEqual([
{ old: { highway: 'no' } },
]);
});
it('returns 1:1 replacement', () => {
expect(getDeprecatedTags({ amenity: 'toilet' }, deprecated)).toStrictEqual([
{ old: { amenity: 'toilet' }, replace: { amenity: 'toilets' } },
]);
});
it('returns 1:1 wildcard', () => {
expect(getDeprecatedTags({ speedlimit: '50' }, deprecated)).toStrictEqual([
{ old: { speedlimit: '*' }, replace: { maxspeed: '$1' } },
]);
});
it('returns 1:2 total replacement', () => {
expect(
getDeprecatedTags({ man_made: 'water_tank' }, deprecated),
).toStrictEqual([
{
old: { man_made: 'water_tank' },
replace: { man_made: 'storage_tank', content: 'water' },
},
]);
});
it('returns 1:2 partial replacement', () => {
expect(
getDeprecatedTags(
{ man_made: 'water_tank', content: 'water' },
deprecated,
),
).toStrictEqual([
{
old: { man_made: 'water_tank' },
replace: { man_made: 'storage_tank', content: 'water' },
},
]);
});
it('returns 2:1 replacement', () => {
expect(
getDeprecatedTags(
{ amenity: 'gambling', gambling: 'casino' },
deprecated,
),
).toStrictEqual([
{
old: { amenity: 'gambling', gambling: 'casino' },
replace: { amenity: 'casino' },
},
]);
});
});
describe('deprecatedTagValuesByKey', () => {
it('groups simple deprecations by key', () => {
expect(deprecatedTagValuesByKey(deprecated)).toStrictEqual({
amenity: ['toilet'], // `gambling` not included
highway: ['no'],
man_made: ['water_tank'],
});
});
});
-54
View File
@@ -226,60 +226,6 @@ describe('iD.osmEntity', function () {
});
});
describe('#deprecatedTags', function () {
var deprecated = [
{ old: { highway: 'no' } },
{ old: { amenity: 'toilet' }, replace: { amenity: 'toilets' } },
{ old: { speedlimit: '*' }, replace: { maxspeed: '$1' } },
{ old: { man_made: 'water_tank' }, replace: { man_made: 'storage_tank', content: 'water' } },
{ old: { amenity: 'gambling', gambling: 'casino' }, replace: { amenity: 'casino' } }
];
it('returns none if entity has no tags', function () {
expect(iD.osmEntity().deprecatedTags(deprecated)).to.eql([]);
});
it('returns none when no tags are deprecated', function () {
expect(iD.osmEntity({ tags: { amenity: 'toilets' } }).deprecatedTags(deprecated)).to.eql([]);
});
it('returns 1:0 replacement', function () {
expect(iD.osmEntity({ tags: { highway: 'no' } }).deprecatedTags(deprecated)).to.eql(
[{ old: { highway: 'no' } }]
);
});
it('returns 1:1 replacement', function () {
expect(iD.osmEntity({ tags: { amenity: 'toilet' } }).deprecatedTags(deprecated)).to.eql(
[{ old: { amenity: 'toilet' }, replace: { amenity: 'toilets' } }]
);
});
it('returns 1:1 wildcard', function () {
expect(iD.osmEntity({ tags: { speedlimit: '50' } }).deprecatedTags(deprecated)).to.eql(
[{ old: { speedlimit: '*' }, replace: { maxspeed: '$1' } }]
);
});
it('returns 1:2 total replacement', function () {
expect(iD.osmEntity({ tags: { man_made: 'water_tank' } }).deprecatedTags(deprecated)).to.eql(
[{ old: { man_made: 'water_tank' }, replace: { man_made: 'storage_tank', content: 'water' } }]
);
});
it('returns 1:2 partial replacement', function () {
expect(iD.osmEntity({ tags: { man_made: 'water_tank', content: 'water' } }).deprecatedTags(deprecated)).to.eql(
[{ old: { man_made: 'water_tank' }, replace: { man_made: 'storage_tank', content: 'water' } }]
);
});
it('returns 2:1 replacement', function () {
expect(iD.osmEntity({ tags: { amenity: 'gambling', gambling: 'casino' } }).deprecatedTags(deprecated)).to.eql(
[{ old: { amenity: 'gambling', gambling: 'casino' }, replace: { amenity: 'casino' } }]
);
});
});
describe('#hasInterestingTags', function () {
it('returns false if the entity has no tags', function () {
expect(iD.osmEntity().hasInterestingTags()).to.equal(false);