forked from MapComplete/MapComplete
Themes: add validation for duplicate presets, fix #1582
This commit is contained in:
parent
fc6160c760
commit
2e8a3311e7
5 changed files with 83 additions and 18 deletions
|
@ -144,14 +144,7 @@
|
||||||
"width": 5
|
"width": 5
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"presets": [
|
"=presets": [ ],
|
||||||
{
|
|
||||||
"tags": [
|
|
||||||
"shop=yes",
|
|
||||||
"dog=yes"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": {
|
"source": {
|
||||||
"=osmTags": {
|
"=osmTags": {
|
||||||
"and": [
|
"and": [
|
||||||
|
@ -227,4 +220,4 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"credits": "Niels Elgaard Larsen"
|
"credits": "Niels Elgaard Larsen"
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
"sameAs": "vending_machine"
|
"sameAs": "vending_machine"
|
||||||
},
|
},
|
||||||
"minzoom": 18,
|
"minzoom": 18,
|
||||||
|
"=presets": [],
|
||||||
"source": {
|
"source": {
|
||||||
"osmTags": {
|
"osmTags": {
|
||||||
"and": [
|
"and": [
|
||||||
|
@ -61,4 +62,4 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRende
|
||||||
import Validators from "../../../UI/InputElement/Validators"
|
import Validators from "../../../UI/InputElement/Validators"
|
||||||
import TagRenderingConfig from "../TagRenderingConfig"
|
import TagRenderingConfig from "../TagRenderingConfig"
|
||||||
import { parse as parse_html } from "node-html-parser"
|
import { parse as parse_html } from "node-html-parser"
|
||||||
|
import PresetConfig from "../PresetConfig"
|
||||||
|
import { TagsFilter } from "../../../Logic/Tags/TagsFilter"
|
||||||
|
|
||||||
class ValidateLanguageCompleteness extends DesugaringStep<any> {
|
class ValidateLanguageCompleteness extends DesugaringStep<any> {
|
||||||
private readonly _languages: string[]
|
private readonly _languages: string[]
|
||||||
|
@ -167,9 +169,9 @@ class ValidateTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
json: LayoutConfigJson,
|
json: LayoutConfigJson,
|
||||||
context: string
|
context: string
|
||||||
): { result: LayoutConfigJson; errors: string[]; warnings: string[]; information: string[] } {
|
): { result: LayoutConfigJson; errors: string[]; warnings: string[]; information: string[] } {
|
||||||
const errors = []
|
const errors: string[] = []
|
||||||
const warnings = []
|
const warnings: string[] = []
|
||||||
const information = []
|
const information: string[] = []
|
||||||
|
|
||||||
const theme = new LayoutConfig(json, this._isBuiltin)
|
const theme = new LayoutConfig(json, this._isBuiltin)
|
||||||
|
|
||||||
|
@ -245,7 +247,7 @@ class ValidateTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
information
|
information
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const dups = Utils.Dupiclates(json.layers.map((layer) => layer["id"]))
|
const dups = Utils.Duplicates(json.layers.map((layer) => layer["id"]))
|
||||||
if (dups.length > 0) {
|
if (dups.length > 0) {
|
||||||
errors.push(
|
errors.push(
|
||||||
`The theme ${json.id} defines multiple layers with id ${dups.join(", ")}`
|
`The theme ${json.id} defines multiple layers with id ${dups.join(", ")}`
|
||||||
|
@ -275,6 +277,10 @@ class ValidateTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
errors.push(e)
|
errors.push(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (theme.id !== "personal") {
|
||||||
|
new DetectDuplicatePresets().convertJoin(theme, context, errors, warnings, information)
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
result: json,
|
result: json,
|
||||||
errors,
|
errors,
|
||||||
|
@ -889,7 +895,7 @@ export class ValidateLayer extends DesugaringStep<LayerConfigJson> {
|
||||||
{
|
{
|
||||||
// duplicate ids in tagrenderings check
|
// duplicate ids in tagrenderings check
|
||||||
const duplicates = Utils.Dedup(
|
const duplicates = Utils.Dedup(
|
||||||
Utils.Dupiclates(Utils.NoNull((json.tagRenderings ?? []).map((tr) => tr["id"])))
|
Utils.Duplicates(Utils.NoNull((json.tagRenderings ?? []).map((tr) => tr["id"])))
|
||||||
)
|
)
|
||||||
if (duplicates.length > 0) {
|
if (duplicates.length > 0) {
|
||||||
console.log(json.tagRenderings)
|
console.log(json.tagRenderings)
|
||||||
|
@ -985,7 +991,7 @@ export class ValidateLayer extends DesugaringStep<LayerConfigJson> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const duplicateIds = Utils.Dupiclates(
|
const duplicateIds = Utils.Duplicates(
|
||||||
(json.tagRenderings ?? [])
|
(json.tagRenderings ?? [])
|
||||||
?.map((f) => f["id"])
|
?.map((f) => f["id"])
|
||||||
.filter((id) => id !== "questions")
|
.filter((id) => id !== "questions")
|
||||||
|
@ -1243,3 +1249,68 @@ export class DetectDuplicateFilters extends DesugaringStep<{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class DetectDuplicatePresets extends DesugaringStep<LayoutConfig> {
|
||||||
|
constructor() {
|
||||||
|
super(
|
||||||
|
"Detects mappings which have identical (english) names or identical mappings.",
|
||||||
|
["presets"],
|
||||||
|
"DetectDuplicatePresets"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
convert(
|
||||||
|
json: LayoutConfig,
|
||||||
|
context: string
|
||||||
|
): {
|
||||||
|
result: LayoutConfig
|
||||||
|
errors?: string[]
|
||||||
|
warnings?: string[]
|
||||||
|
information?: string[]
|
||||||
|
} {
|
||||||
|
const presets: PresetConfig[] = [].concat(...json.layers.map((l) => l.presets))
|
||||||
|
|
||||||
|
const errors = []
|
||||||
|
const enNames = presets.map((p) => p.title.textFor("en"))
|
||||||
|
if (new Set(enNames).size != enNames.length) {
|
||||||
|
const dups = Utils.Duplicates(enNames)
|
||||||
|
const layersWithDup = json.layers.filter((l) =>
|
||||||
|
l.presets.some((p) => dups.indexOf(p.title.textFor("en")) >= 0)
|
||||||
|
)
|
||||||
|
const layerIds = layersWithDup.map((l) => l.id)
|
||||||
|
errors.push(
|
||||||
|
`At ${context}: this themes has multiple presets which are named:${dups}, namely layers ${layerIds.join(
|
||||||
|
", "
|
||||||
|
)} this is confusing for contributors and is probably the result of reusing the same layer multiple times. Use \`{"override": {"=presets": []}}\` to remove some presets`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const optimizedTags = <TagsFilter[]>presets.map((p) => new And(p.tags).optimize())
|
||||||
|
for (let i = 0; i < presets.length; i++) {
|
||||||
|
const presetATags = optimizedTags[i]
|
||||||
|
const presetA = presets[i]
|
||||||
|
for (let j = i + 1; j < presets.length; j++) {
|
||||||
|
const presetBTags = optimizedTags[j]
|
||||||
|
const presetB = presets[j]
|
||||||
|
if (
|
||||||
|
Utils.SameObject(presetATags, presetBTags) &&
|
||||||
|
Utils.sameList(
|
||||||
|
presetA.preciseInput.snapToLayers,
|
||||||
|
presetB.preciseInput.snapToLayers
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
errors.push(
|
||||||
|
`At ${context}: this themes has multiple presets with the same tags: ${presetATags.asHumanString(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
{}
|
||||||
|
)}, namely the preset '${presets[i].title.textFor("en")}' and '${presets[
|
||||||
|
j
|
||||||
|
].title.textFor("en")}'`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { errors, result: json }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -359,7 +359,7 @@ export default class LayerConfig extends WithContextLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const duplicateIds = Utils.Dupiclates(this.filters.map((f) => f.id))
|
const duplicateIds = Utils.Duplicates(this.filters.map((f) => f.id))
|
||||||
if (duplicateIds.length > 0) {
|
if (duplicateIds.length > 0) {
|
||||||
throw `Some filters have a duplicate id: ${duplicateIds} (at ${context}.filters)`
|
throw `Some filters have a duplicate id: ${duplicateIds} (at ${context}.filters)`
|
||||||
}
|
}
|
||||||
|
|
|
@ -387,7 +387,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
||||||
return newArr
|
return newArr
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Dupiclates(arr: string[]): string[] {
|
public static Duplicates(arr: string[]): string[] {
|
||||||
if (arr === undefined) {
|
if (arr === undefined) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue