Merge develop

This commit is contained in:
Pieter Vander Vennet 2024-02-15 17:48:26 +01:00
commit f0823f4c4d
524 changed files with 18747 additions and 8546 deletions

View file

@ -1,4 +1,14 @@
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"
@ -19,7 +29,7 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
super(
"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
}
@ -61,6 +71,7 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
for (const name of names) {
const found = Utils.Clone(state.sharedLayers.get(name))
found["_basedOn"] = name
if (found === undefined) {
reportNotFound(name)
continue
@ -70,15 +81,16 @@ 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){
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)
@ -90,14 +102,18 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
} 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"
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
@ -111,9 +127,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
}
@ -122,7 +138,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
}
@ -131,10 +147,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
}
@ -145,8 +161,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
@ -163,7 +179,7 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
super(
"Adds the default layers, namely: " + Constants.added_by_default.join(", "),
["layers"],
"AddDefaultLayers",
"AddDefaultLayers"
)
this._state = state
}
@ -186,10 +202,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
}
@ -205,14 +221,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
}
@ -247,7 +263,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)
@ -266,7 +282,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"
)
}
@ -281,11 +297,11 @@ class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
super(
"Applies 'overrideAll' onto every 'layer'. The 'overrideAll'-field is removed afterwards",
["overrideAll", "layers"],
"ApplyOverrideAll",
"ApplyOverrideAll"
)
}
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
convert(json: LayoutConfigJson, _: ConversionContext): LayoutConfigJson {
const overrideAll = json.overrideAll
if (overrideAll === undefined) {
return json
@ -309,8 +325,9 @@ class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
if (!layer.tagRenderings) {
layer.tagRenderings = tagRenderingsPlus
} else {
let index = layer.tagRenderings.findIndex(tr => tr["id"] === "leftover-questions")
let index = layer.tagRenderings.findIndex(
(tr) => tr["id"] === "leftover-questions"
)
if (index < 0) {
index = layer.tagRenderings.length - 1
}
@ -337,7 +354,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
}
@ -345,7 +362,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))
@ -368,7 +385,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) {
@ -405,10 +422,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(","),
]
@ -424,7 +441,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)
@ -445,14 +462,12 @@ 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
)
}
}
@ -494,7 +509,7 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
super(
"Generates a warning if a theme uses an unsubstituted layer",
["layers"],
"WarnForUnsubstitutedLayersInTheme",
"WarnForUnsubstitutedLayersInTheme"
)
}
@ -506,7 +521,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
}
@ -530,16 +545,64 @@ 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
}
}
class PostvalidateTheme extends DesugaringStep<LayoutConfigJson> {
private readonly _state: DesugaringContext
constructor(state: DesugaringContext) {
super("Various validation steps when everything is done", [], "PostvalidateTheme")
this._state = state
}
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
for (const l of json.layers) {
const layer = <LayerConfigJson>l
const basedOn = <string>layer["_basedOn"]
const basedOnDef = this._state.sharedLayers.get(basedOn)
if (!basedOn) {
continue
}
if (layer["name"] === null) {
continue
}
const sameBasedOn = <LayerConfigJson[]>(
json.layers.filter(
(l) => l["_basedOn"] === layer["_basedOn"] && l["id"] !== layer.id
)
)
const minZoomAll = Math.min(...sameBasedOn.map((sbo) => sbo.minzoom))
const sameNameDetected = sameBasedOn.some(
(same) => JSON.stringify(layer["name"]) === JSON.stringify(same["name"])
)
if (!sameNameDetected) {
// The name is unique, so it'll won't be confusing
continue
}
if (minZoomAll < layer.minzoom) {
context.err(
"There are multiple layers based on " +
basedOn +
". The layer with id " +
layer.id +
" has a minzoom of " +
layer.minzoom +
", and has a name set. Another similar layer has a lower minzoom. As such, the layer selection might show 'zoom in to see features' even though some of the features are already visible. Set `\"name\": null` for this layer and eventually remove the 'name':null for the other layer."
)
}
}
return json
}
}
export class PrepareTheme extends Fuse<LayoutConfigJson> {
private state: DesugaringContext
@ -547,7 +610,7 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
state: DesugaringContext,
options?: {
skipDefaultLayers: false | boolean
},
}
) {
super(
"Fully prepares and expands a theme",
@ -559,7 +622,8 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
new SetDefault("socialImage", "assets/SocialImage.png", true),
// We expand all tagrenderings first...
new On("layers", new Each(new PrepareLayer(state))),
// Then we apply the override all. Note that it'll cheat with tagRenderings+
// 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))),
@ -568,6 +632,7 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
: new AddDefaultLayers(state),
new AddDependencyLayersToTheme(state),
new AddImportLayers(),
new PostvalidateTheme(state)
)
this.state = state
}
@ -582,13 +647,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
}