forked from MapComplete/MapComplete
		
	Merge develop
This commit is contained in:
		
						commit
						c672fe7668
					
				
					 138 changed files with 14304 additions and 1299 deletions
				
			
		| 
						 | 
				
			
			@ -1,14 +1,4 @@
 | 
			
		|||
import {
 | 
			
		||||
    Concat,
 | 
			
		||||
    Conversion,
 | 
			
		||||
    DesugaringContext,
 | 
			
		||||
    DesugaringStep,
 | 
			
		||||
    Each,
 | 
			
		||||
    Fuse,
 | 
			
		||||
    On,
 | 
			
		||||
    Pass,
 | 
			
		||||
    SetDefault,
 | 
			
		||||
} from "./Conversion"
 | 
			
		||||
import { Concat, Conversion, DesugaringContext, DesugaringStep, Each, Fuse, On, Pass, SetDefault } from "./Conversion"
 | 
			
		||||
import { LayoutConfigJson } from "../Json/LayoutConfigJson"
 | 
			
		||||
import { PrepareLayer } from "./PrepareLayer"
 | 
			
		||||
import { LayerConfigJson } from "../Json/LayerConfigJson"
 | 
			
		||||
| 
						 | 
				
			
			@ -27,9 +17,9 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
 | 
			
		|||
 | 
			
		||||
    constructor(state: DesugaringContext) {
 | 
			
		||||
        super(
 | 
			
		||||
            "Converts the identifier of a builtin layer into the actual layer, or converts a 'builtin' syntax with override in the fully expanded form",
 | 
			
		||||
            "Converts the identifier of a builtin layer into the actual layer, or converts a 'builtin' syntax with override in the fully expanded form. Note that 'tagRenderings+' will be inserted before 'leftover-questions'",
 | 
			
		||||
            [],
 | 
			
		||||
            "SubstituteLayer"
 | 
			
		||||
            "SubstituteLayer",
 | 
			
		||||
        )
 | 
			
		||||
        this._state = state
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -80,21 +70,35 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
 | 
			
		|||
                (found["tagRenderings"] ?? []).length > 0
 | 
			
		||||
            ) {
 | 
			
		||||
                context.err(
 | 
			
		||||
                    `When overriding a layer, an override is not allowed to override into tagRenderings. Use "+tagRenderings" or "tagRenderings+" instead to prepend or append some questions.`
 | 
			
		||||
                    `When overriding a layer, an override is not allowed to override into tagRenderings. Use "+tagRenderings" or "tagRenderings+" instead to prepend or append some questions.`,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            try {
 | 
			
		||||
 | 
			
		||||
                const trPlus = json["override"]["tagRenderings+"]
 | 
			
		||||
                if(trPlus){
 | 
			
		||||
                    let index = found.tagRenderings.findIndex(tr => tr["id"] === "leftover-questions")
 | 
			
		||||
                    if(index < 0){
 | 
			
		||||
                        index = found.tagRenderings.length
 | 
			
		||||
                    }
 | 
			
		||||
                    found.tagRenderings.splice(index, 0, ...trPlus)
 | 
			
		||||
                    delete json["override"]["tagRenderings+"]
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Utils.Merge(json["override"], found)
 | 
			
		||||
                layers.push(found)
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                context.err(
 | 
			
		||||
                    `Could not apply an override due to: ${e}.\nThe override is: ${JSON.stringify(
 | 
			
		||||
                        json["override"]
 | 
			
		||||
                    )}`
 | 
			
		||||
                        json["override"],
 | 
			
		||||
                    )}`,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (json["hideTagRenderingsWithLabels"]) {
 | 
			
		||||
                if (typeof json["hideTagRenderingsWithLabels"] === "string") {
 | 
			
		||||
                    throw "At " + context + ".hideTagRenderingsWithLabels should be a list containing strings, you specified a string"
 | 
			
		||||
                }
 | 
			
		||||
                const hideLabels: Set<string> = new Set(json["hideTagRenderingsWithLabels"])
 | 
			
		||||
                // These labels caused at least one deletion
 | 
			
		||||
                const usedLabels: Set<string> = new Set<string>()
 | 
			
		||||
| 
						 | 
				
			
			@ -107,9 +111,9 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
 | 
			
		|||
                            usedLabels.add(labels[forbiddenLabel])
 | 
			
		||||
                            context.info(
 | 
			
		||||
                                "Dropping tagRendering " +
 | 
			
		||||
                                    tr["id"] +
 | 
			
		||||
                                    " as it has a forbidden label: " +
 | 
			
		||||
                                    labels[forbiddenLabel]
 | 
			
		||||
                                tr["id"] +
 | 
			
		||||
                                " as it has a forbidden label: " +
 | 
			
		||||
                                labels[forbiddenLabel],
 | 
			
		||||
                            )
 | 
			
		||||
                            continue
 | 
			
		||||
                        }
 | 
			
		||||
| 
						 | 
				
			
			@ -118,7 +122,7 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
 | 
			
		|||
                    if (hideLabels.has(tr["id"])) {
 | 
			
		||||
                        usedLabels.add(tr["id"])
 | 
			
		||||
                        context.info(
 | 
			
		||||
                            "Dropping tagRendering " + tr["id"] + " as its id is a forbidden label"
 | 
			
		||||
                            "Dropping tagRendering " + tr["id"] + " as its id is a forbidden label",
 | 
			
		||||
                        )
 | 
			
		||||
                        continue
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -127,10 +131,10 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
 | 
			
		|||
                        usedLabels.add(tr["group"])
 | 
			
		||||
                        context.info(
 | 
			
		||||
                            "Dropping tagRendering " +
 | 
			
		||||
                                tr["id"] +
 | 
			
		||||
                                " as its group `" +
 | 
			
		||||
                                tr["group"] +
 | 
			
		||||
                                "` is a forbidden label"
 | 
			
		||||
                            tr["id"] +
 | 
			
		||||
                            " as its group `" +
 | 
			
		||||
                            tr["group"] +
 | 
			
		||||
                            "` is a forbidden label",
 | 
			
		||||
                        )
 | 
			
		||||
                        continue
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -141,8 +145,8 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
 | 
			
		|||
                if (unused.length > 0) {
 | 
			
		||||
                    context.err(
 | 
			
		||||
                        "This theme specifies that certain tagrenderings have to be removed based on forbidden layers. One or more of these layers did not match any tagRenderings and caused no deletions: " +
 | 
			
		||||
                            unused.join(", ") +
 | 
			
		||||
                            "\n   This means that this label can be removed or that the original tagRendering that should be deleted does not have this label anymore"
 | 
			
		||||
                        unused.join(", ") +
 | 
			
		||||
                        "\n   This means that this label can be removed or that the original tagRendering that should be deleted does not have this label anymore",
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
                found.tagRenderings = filtered
 | 
			
		||||
| 
						 | 
				
			
			@ -159,7 +163,7 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
 | 
			
		|||
        super(
 | 
			
		||||
            "Adds the default layers, namely: " + Constants.added_by_default.join(", "),
 | 
			
		||||
            ["layers"],
 | 
			
		||||
            "AddDefaultLayers"
 | 
			
		||||
            "AddDefaultLayers",
 | 
			
		||||
        )
 | 
			
		||||
        this._state = state
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -183,10 +187,10 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
 | 
			
		|||
            if (alreadyLoaded.has(v.id)) {
 | 
			
		||||
                context.warn(
 | 
			
		||||
                    "Layout " +
 | 
			
		||||
                        context +
 | 
			
		||||
                        " already has a layer with name " +
 | 
			
		||||
                        v.id +
 | 
			
		||||
                        "; skipping inclusion of this builtin layer"
 | 
			
		||||
                    context +
 | 
			
		||||
                    " already has a layer with name " +
 | 
			
		||||
                    v.id +
 | 
			
		||||
                    "; skipping inclusion of this builtin layer",
 | 
			
		||||
                )
 | 
			
		||||
                continue
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -202,14 +206,14 @@ class AddImportLayers extends DesugaringStep<LayoutConfigJson> {
 | 
			
		|||
        super(
 | 
			
		||||
            "For every layer in the 'layers'-list, create a new layer which'll import notes. (Note that priviliged layers and layers which have a geojson-source set are ignored)",
 | 
			
		||||
            ["layers"],
 | 
			
		||||
            "AddImportLayers"
 | 
			
		||||
            "AddImportLayers",
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
 | 
			
		||||
        if (!(json.enableNoteImports ?? true)) {
 | 
			
		||||
            context.info(
 | 
			
		||||
                "Not creating a note import layers for theme " + json.id + " as they are disabled"
 | 
			
		||||
                "Not creating a note import layers for theme " + json.id + " as they are disabled",
 | 
			
		||||
            )
 | 
			
		||||
            return json
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -244,7 +248,7 @@ class AddImportLayers extends DesugaringStep<LayoutConfigJson> {
 | 
			
		|||
            try {
 | 
			
		||||
                const importLayerResult = creator.convert(
 | 
			
		||||
                    layer,
 | 
			
		||||
                    context.inOperation(this.name).enter(i1)
 | 
			
		||||
                    context.inOperation(this.name).enter(i1),
 | 
			
		||||
                )
 | 
			
		||||
                if (importLayerResult !== undefined) {
 | 
			
		||||
                    json.layers.push(importLayerResult)
 | 
			
		||||
| 
						 | 
				
			
			@ -263,7 +267,7 @@ class AddContextToTranslationsInLayout extends DesugaringStep<LayoutConfigJson>
 | 
			
		|||
        super(
 | 
			
		||||
            "Adds context to translations, including the prefix 'themes:json.id'; this is to make sure terms in an 'overrides' or inline layer are linkable too",
 | 
			
		||||
            ["_context"],
 | 
			
		||||
            "AddContextToTranlationsInLayout"
 | 
			
		||||
            "AddContextToTranlationsInLayout",
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -278,7 +282,7 @@ class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
 | 
			
		|||
        super(
 | 
			
		||||
            "Applies 'overrideAll' onto every 'layer'. The 'overrideAll'-field is removed afterwards",
 | 
			
		||||
            ["overrideAll", "layers"],
 | 
			
		||||
            "ApplyOverrideAll"
 | 
			
		||||
            "ApplyOverrideAll",
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -292,9 +296,29 @@ class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
 | 
			
		|||
 | 
			
		||||
        delete json.overrideAll
 | 
			
		||||
        const newLayers = []
 | 
			
		||||
 | 
			
		||||
        let tagRenderingsPlus = undefined
 | 
			
		||||
        if (overrideAll["tagRenderings+"] !== undefined) {
 | 
			
		||||
            tagRenderingsPlus = overrideAll["tagRenderings+"]
 | 
			
		||||
            delete overrideAll["tagRenderings+"]
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let layer of json.layers) {
 | 
			
		||||
            layer = Utils.Clone(<LayerConfigJson>layer)
 | 
			
		||||
            Utils.Merge(overrideAll, layer)
 | 
			
		||||
            if (tagRenderingsPlus) {
 | 
			
		||||
                if (!layer.tagRenderings) {
 | 
			
		||||
                    layer.tagRenderings = tagRenderingsPlus
 | 
			
		||||
                } else {
 | 
			
		||||
 | 
			
		||||
                    let index = layer.tagRenderings.findIndex(tr => tr["id"] === "leftover-questions")
 | 
			
		||||
                    if (index < 0) {
 | 
			
		||||
                        index = layer.tagRenderings.length - 1
 | 
			
		||||
                    }
 | 
			
		||||
                    layer.tagRenderings.splice(index, 0, ...tagRenderingsPlus)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            newLayers.push(layer)
 | 
			
		||||
        }
 | 
			
		||||
        json.layers = newLayers
 | 
			
		||||
| 
						 | 
				
			
			@ -314,7 +338,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
 | 
			
		|||
            Some layers (e.g. \`all_buildings_and_walls\' or \'streets_with_a_name\') are invisible, so by default, \'force_load\' is set too.
 | 
			
		||||
            `,
 | 
			
		||||
            ["layers"],
 | 
			
		||||
            "AddDependencyLayersToTheme"
 | 
			
		||||
            "AddDependencyLayersToTheme",
 | 
			
		||||
        )
 | 
			
		||||
        this._state = state
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -322,7 +346,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
 | 
			
		|||
    private static CalculateDependencies(
 | 
			
		||||
        alreadyLoaded: LayerConfigJson[],
 | 
			
		||||
        allKnownLayers: Map<string, LayerConfigJson>,
 | 
			
		||||
        themeId: string
 | 
			
		||||
        themeId: string,
 | 
			
		||||
    ): { config: LayerConfigJson; reason: string }[] {
 | 
			
		||||
        const dependenciesToAdd: { config: LayerConfigJson; reason: string }[] = []
 | 
			
		||||
        const loadedLayerIds: Set<string> = new Set<string>(alreadyLoaded.map((l) => l.id))
 | 
			
		||||
| 
						 | 
				
			
			@ -345,7 +369,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
 | 
			
		|||
            for (const layerConfig of alreadyLoaded) {
 | 
			
		||||
                try {
 | 
			
		||||
                    const layerDeps = DependencyCalculator.getLayerDependencies(
 | 
			
		||||
                        new LayerConfig(layerConfig, themeId + "(dependencies)")
 | 
			
		||||
                        new LayerConfig(layerConfig, themeId + "(dependencies)"),
 | 
			
		||||
                    )
 | 
			
		||||
                    dependencies.push(...layerDeps)
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
| 
						 | 
				
			
			@ -382,10 +406,10 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
 | 
			
		|||
                if (dep === undefined) {
 | 
			
		||||
                    const message = [
 | 
			
		||||
                        "Loading a dependency failed: layer " +
 | 
			
		||||
                            unmetDependency.neededLayer +
 | 
			
		||||
                            " is not found, neither as layer of " +
 | 
			
		||||
                            themeId +
 | 
			
		||||
                            " nor as builtin layer.",
 | 
			
		||||
                        unmetDependency.neededLayer +
 | 
			
		||||
                        " is not found, neither as layer of " +
 | 
			
		||||
                        themeId +
 | 
			
		||||
                        " nor as builtin layer.",
 | 
			
		||||
                        reason,
 | 
			
		||||
                        "Loaded layers are: " + alreadyLoaded.map((l) => l.id).join(","),
 | 
			
		||||
                    ]
 | 
			
		||||
| 
						 | 
				
			
			@ -401,7 +425,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
 | 
			
		|||
                })
 | 
			
		||||
                loadedLayerIds.add(dep.id)
 | 
			
		||||
                unmetDependencies = unmetDependencies.filter(
 | 
			
		||||
                    (d) => d.neededLayer !== unmetDependency.neededLayer
 | 
			
		||||
                    (d) => d.neededLayer !== unmetDependency.neededLayer,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        } while (unmetDependencies.length > 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -422,14 +446,14 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
 | 
			
		|||
        const dependencies = AddDependencyLayersToTheme.CalculateDependencies(
 | 
			
		||||
            layers,
 | 
			
		||||
            allKnownLayers,
 | 
			
		||||
            theme.id
 | 
			
		||||
            theme.id,
 | 
			
		||||
        )
 | 
			
		||||
        for (const dependency of dependencies) {
 | 
			
		||||
        }
 | 
			
		||||
        if (dependencies.length > 0) {
 | 
			
		||||
            for (const dependency of dependencies) {
 | 
			
		||||
                context.info(
 | 
			
		||||
                    "Added " + dependency.config.id + " to the theme. " + dependency.reason
 | 
			
		||||
                    "Added " + dependency.config.id + " to the theme. " + dependency.reason,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -471,7 +495,7 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
 | 
			
		|||
        super(
 | 
			
		||||
            "Generates a warning if a theme uses an unsubstituted layer",
 | 
			
		||||
            ["layers"],
 | 
			
		||||
            "WarnForUnsubstitutedLayersInTheme"
 | 
			
		||||
            "WarnForUnsubstitutedLayersInTheme",
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -483,7 +507,7 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
 | 
			
		|||
            context
 | 
			
		||||
                .enter("layers")
 | 
			
		||||
                .err(
 | 
			
		||||
                    "No layers are defined. You must define at least one layer to have a valid theme"
 | 
			
		||||
                    "No layers are defined. You must define at least one layer to have a valid theme",
 | 
			
		||||
                )
 | 
			
		||||
            return json
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -507,10 +531,10 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
 | 
			
		|||
 | 
			
		||||
            context.warn(
 | 
			
		||||
                "The theme " +
 | 
			
		||||
                    json.id +
 | 
			
		||||
                    " has an inline layer: " +
 | 
			
		||||
                    layer["id"] +
 | 
			
		||||
                    ". This is discouraged."
 | 
			
		||||
                json.id +
 | 
			
		||||
                " has an inline layer: " +
 | 
			
		||||
                layer["id"] +
 | 
			
		||||
                ". This is discouraged.",
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        return json
 | 
			
		||||
| 
						 | 
				
			
			@ -519,11 +543,12 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
 | 
			
		|||
 | 
			
		||||
export class PrepareTheme extends Fuse<LayoutConfigJson> {
 | 
			
		||||
    private state: DesugaringContext
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        state: DesugaringContext,
 | 
			
		||||
        options?: {
 | 
			
		||||
            skipDefaultLayers: false | boolean
 | 
			
		||||
        }
 | 
			
		||||
        },
 | 
			
		||||
    ) {
 | 
			
		||||
        super(
 | 
			
		||||
            "Fully prepares and expands a theme",
 | 
			
		||||
| 
						 | 
				
			
			@ -536,6 +561,7 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
 | 
			
		|||
            // We expand all tagrenderings first...
 | 
			
		||||
            new On("layers", new Each(new PrepareLayer(state))),
 | 
			
		||||
            // Then we apply the override all. We must first expand everything in case that we override something in an expanded tag
 | 
			
		||||
            // Note that it'll cheat with tagRenderings+
 | 
			
		||||
            new ApplyOverrideAll(),
 | 
			
		||||
            // And then we prepare all the layers _again_ in case that an override all contained unexpanded tagrenderings!
 | 
			
		||||
            new On("layers", new Each(new PrepareLayer(state))),
 | 
			
		||||
| 
						 | 
				
			
			@ -543,7 +569,7 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
 | 
			
		|||
                ? new Pass("AddDefaultLayers is disabled due to the set flag")
 | 
			
		||||
                : new AddDefaultLayers(state),
 | 
			
		||||
            new AddDependencyLayersToTheme(state),
 | 
			
		||||
            new AddImportLayers()
 | 
			
		||||
            new AddImportLayers(),
 | 
			
		||||
        )
 | 
			
		||||
        this.state = state
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -558,13 +584,13 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
 | 
			
		|||
        const needsNodeDatabase = result.layers?.some((l: LayerConfigJson) =>
 | 
			
		||||
            l.tagRenderings?.some((tr) =>
 | 
			
		||||
                ValidationUtils.getSpecialVisualisations(<any>tr)?.some(
 | 
			
		||||
                    (special) => special.needsNodeDatabase
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
                    (special) => special.needsNodeDatabase,
 | 
			
		||||
                ),
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
        if (needsNodeDatabase) {
 | 
			
		||||
            context.info(
 | 
			
		||||
                "Setting 'enableNodeDatabase' as this theme uses a special visualisation which needs to keep track of _all_ nodes"
 | 
			
		||||
                "Setting 'enableNodeDatabase' as this theme uses a special visualisation which needs to keep track of _all_ nodes",
 | 
			
		||||
            )
 | 
			
		||||
            result.enableNodeDatabase = true
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@ import { ConversionContext } from "./ConversionContext"
 | 
			
		|||
import * as eli from "../../../assets/editor-layer-index.json"
 | 
			
		||||
import { AvailableRasterLayers } from "../../RasterLayers"
 | 
			
		||||
import Back from "../../../assets/svg/Back.svelte"
 | 
			
		||||
import PointRenderingConfigJson from "../Json/PointRenderingConfigJson"
 | 
			
		||||
 | 
			
		||||
class ValidateLanguageCompleteness extends DesugaringStep<LayoutConfig> {
 | 
			
		||||
    private readonly _languages: string[]
 | 
			
		||||
| 
						 | 
				
			
			@ -177,6 +178,9 @@ export class ValidateTheme extends DesugaringStep<LayoutConfigJson> {
 | 
			
		|||
        if (!json.title) {
 | 
			
		||||
            context.enter("title").err(`The theme ${json.id} does not have a title defined.`)
 | 
			
		||||
        }
 | 
			
		||||
        if(!json.icon){
 | 
			
		||||
            context.enter("icon").err("A theme should have an icon")
 | 
			
		||||
        }
 | 
			
		||||
        if (this._isBuiltin && this._extractImages !== undefined) {
 | 
			
		||||
            // Check images: are they local, are the licenses there, is the theme icon square, ...
 | 
			
		||||
            const images = this._extractImages.convert(json, context.inOperation("ValidateTheme"))
 | 
			
		||||
| 
						 | 
				
			
			@ -243,7 +247,8 @@ export class ValidateTheme extends DesugaringStep<LayoutConfigJson> {
 | 
			
		|||
                new ValidateLanguageCompleteness("en").convert(theme, context)
 | 
			
		||||
            }
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            context.err(e)
 | 
			
		||||
            console.error(e)
 | 
			
		||||
            context.err("Could not validate the theme due to: " + e)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (theme.id !== "personal") {
 | 
			
		||||
| 
						 | 
				
			
			@ -411,7 +416,7 @@ export class DetectConflictingAddExtraTags extends DesugaringStep<TagRenderingCo
 | 
			
		|||
 | 
			
		||||
            return json
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            context.err(e)
 | 
			
		||||
            context.err("Could not check for conflicting extra tags due to: " + e)
 | 
			
		||||
            return undefined
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1016,6 +1021,7 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
 | 
			
		|||
     */
 | 
			
		||||
    private readonly _path: string
 | 
			
		||||
    private readonly _studioValidations: boolean
 | 
			
		||||
    private readonly _validatePointRendering = new ValidatePointRendering()
 | 
			
		||||
 | 
			
		||||
    constructor(path: string, isBuiltin, doesImageExist, studioValidations) {
 | 
			
		||||
        super("Runs various checks against common mistakes for a layer", [], "PrevalidateLayer")
 | 
			
		||||
| 
						 | 
				
			
			@ -1105,6 +1111,8 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
 | 
			
		|||
            context.enter("pointRendering").err("There are no pointRenderings at all...")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        json.pointRendering?.forEach((pr,i) => this._validatePointRendering.convert(pr, context.enters("pointeRendering", i)))
 | 
			
		||||
 | 
			
		||||
        if (json["mapRendering"]) {
 | 
			
		||||
            context.enter("mapRendering").err("This layer has a legacy 'mapRendering'")
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1409,13 +1417,40 @@ export class ValidateLayerConfig extends DesugaringStep<LayerConfigJson> {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ValidatePointRendering extends DesugaringStep<PointRenderingConfigJson> {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super("Various checks for pointRenderings", [], "ValidatePOintRendering")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    convert(json: PointRenderingConfigJson, context: ConversionContext): PointRenderingConfigJson {
 | 
			
		||||
        if (json.marker === undefined && json.label === undefined) {
 | 
			
		||||
            context.err(`A point rendering should define at least an marker or a label`)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (json["markers"]) {
 | 
			
		||||
            context.enter("markers").err(`Detected a field 'markerS' in pointRendering. It is written as a singular case`)
 | 
			
		||||
        }
 | 
			
		||||
        if (json.marker && !Array.isArray(json.marker)) {
 | 
			
		||||
            context.enter("marker").err(
 | 
			
		||||
                "The marker in a pointRendering should be an array"
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        if (json.location.length == 0) {
 | 
			
		||||
            context.enter("location").err (
 | 
			
		||||
                "A pointRendering should have at least one 'location' to defined where it should be rendered. "
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        return json
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
export class ValidateLayer extends Conversion<
 | 
			
		||||
    LayerConfigJson,
 | 
			
		||||
    { parsed: LayerConfig; raw: LayerConfigJson }
 | 
			
		||||
> {
 | 
			
		||||
    private readonly _skipDefaultLayers: boolean
 | 
			
		||||
    private readonly _prevalidation: PrevalidateLayer
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        path: string,
 | 
			
		||||
        isBuiltin: boolean,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -506,7 +506,7 @@ export interface LayerConfigJson {
 | 
			
		|||
     * If the way is part of a relation, MapComplete will attempt to update this relation as well
 | 
			
		||||
     * question: Should the contributor be able to split ways using this layer?
 | 
			
		||||
     * iftrue: enable the 'split-roads'-component
 | 
			
		||||
     * iffalse: don't enable the split-roads componenet
 | 
			
		||||
     * iffalse: don't enable the split-roads component
 | 
			
		||||
     * ifunset: don't enable the split-roads component
 | 
			
		||||
     * group: editing
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,7 @@ export interface IconConfigJson {
 | 
			
		|||
    /**
 | 
			
		||||
     * question: What icon should be used?
 | 
			
		||||
     * type: icon
 | 
			
		||||
     * suggestions: return ["pin","square","circle","checkmark","clock","close","crosshair","help","home","invalid","location","location_empty","location_locked","note","resolved","ring","scissors","teardrop","teardrop_with_hole_green","triangle"].map(i => ({if: "value="+i, then: i, icon: i}))
 | 
			
		||||
     * suggestions: return Constants.defaultPinIcons.map(i => ({if: "value="+i, then: i, icon: i}))
 | 
			
		||||
     */
 | 
			
		||||
    icon: string | MinimalTagRenderingConfigJson | { builtin: string; override: any }
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -106,8 +106,12 @@ export interface MappingConfigJson {
 | 
			
		|||
    hideInAnswer?: boolean | TagConfigJson
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * question: In what other cases should this item be rendered?
 | 
			
		||||
     *
 | 
			
		||||
     * Also show this 'then'-option if the feature matches these tags.
 | 
			
		||||
     * Ideal for outdated tags.
 | 
			
		||||
     * Ideal for outdated tags or default assumptions. The tags from this options will <b>not</b> be set if the option is chosen!
 | 
			
		||||
     *
 | 
			
		||||
     * ifunset: No other cases when this text is shown
 | 
			
		||||
     */
 | 
			
		||||
    alsoShowIf?: TagConfigJson
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -79,23 +79,7 @@ export default class PointRenderingConfig extends WithContextLoader {
 | 
			
		|||
            }
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        if (json.marker === undefined && json.label === undefined) {
 | 
			
		||||
            throw `At ${context}: A point rendering should define at least an marker or a label`
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (json["markers"]) {
 | 
			
		||||
            throw `At ${context}.markers: detected a field 'markerS' in pointRendering. It is written as a singular case`
 | 
			
		||||
        }
 | 
			
		||||
        if (json.marker && !Array.isArray(json.marker)) {
 | 
			
		||||
            throw `At ${context}.marker: the marker in a pointRendering should be an array`
 | 
			
		||||
        }
 | 
			
		||||
        if (this.location.size == 0) {
 | 
			
		||||
            throw (
 | 
			
		||||
                "A pointRendering should have at least one 'location' to defined where it should be rendered. (At " +
 | 
			
		||||
                context +
 | 
			
		||||
                ".location)"
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        this.marker = (json.marker ?? []).map((m) => new IconConfig(<any>m))
 | 
			
		||||
        if (json.css !== undefined) {
 | 
			
		||||
            this.cssDef = this.tr("css", undefined)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,6 @@ import {
 | 
			
		|||
    QuestionableTagRenderingConfigJson,
 | 
			
		||||
} from "./Json/QuestionableTagRenderingConfigJson"
 | 
			
		||||
import { FixedUiElement } from "../../UI/Base/FixedUiElement"
 | 
			
		||||
import { Paragraph } from "../../UI/Base/Paragraph"
 | 
			
		||||
import Validators, { ValidatorType } from "../../UI/InputElement/Validators"
 | 
			
		||||
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
 | 
			
		||||
import Constants from "../Constants"
 | 
			
		||||
| 
						 | 
				
			
			@ -371,20 +370,9 @@ export default class TagRenderingConfig {
 | 
			
		|||
        let iconClass = commonSize
 | 
			
		||||
        if (!!mapping.icon) {
 | 
			
		||||
            if (typeof mapping.icon === "string" && mapping.icon !== "") {
 | 
			
		||||
                let stripped = mapping.icon
 | 
			
		||||
                if (stripped.endsWith(".svg")) {
 | 
			
		||||
                    stripped = stripped.substring(0, stripped.length - 4)
 | 
			
		||||
                }
 | 
			
		||||
                if (Constants.defaultPinIcons.indexOf(stripped) >= 0) {
 | 
			
		||||
                    icon = "./assets/svg/" + mapping.icon
 | 
			
		||||
                    if (!icon.endsWith(".svg")) {
 | 
			
		||||
                        icon += ".svg"
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    icon = mapping.icon
 | 
			
		||||
                }
 | 
			
		||||
                icon = mapping.icon.trim()
 | 
			
		||||
            } else if (mapping.icon["path"]) {
 | 
			
		||||
                icon = mapping.icon["path"]
 | 
			
		||||
                icon = mapping.icon["path"].trim()
 | 
			
		||||
                iconClass = mapping.icon["class"] ?? iconClass
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -754,12 +742,10 @@ export default class TagRenderingConfig {
 | 
			
		|||
            withRender = [
 | 
			
		||||
                `This rendering asks information about the property `,
 | 
			
		||||
                Link.OsmWiki(this.freeform.key),
 | 
			
		||||
                new Paragraph(
 | 
			
		||||
                    new Combine([
 | 
			
		||||
                        "This is rendered with ",
 | 
			
		||||
                        new FixedUiElement(this.render.txt).SetClass("code font-bold"),
 | 
			
		||||
                    ])
 | 
			
		||||
                ),
 | 
			
		||||
                new Combine([
 | 
			
		||||
                    "This is rendered with ",
 | 
			
		||||
                    new FixedUiElement(this.render.txt).SetClass("code font-bold"),
 | 
			
		||||
                ]),
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue