Themes: move tagRenderings+ above leftover-questions

This commit is contained in:
Pieter Vander Vennet 2024-01-13 03:20:07 +01:00
parent f2d470ff2e
commit f2f041f9d0

View file

@ -1,14 +1,4 @@
import { import { Concat, Conversion, DesugaringContext, DesugaringStep, Each, Fuse, On, Pass, SetDefault } from "./Conversion"
Concat,
Conversion,
DesugaringContext,
DesugaringStep,
Each,
Fuse,
On,
Pass,
SetDefault,
} from "./Conversion"
import { LayoutConfigJson } from "../Json/LayoutConfigJson" import { LayoutConfigJson } from "../Json/LayoutConfigJson"
import { PrepareLayer } from "./PrepareLayer" import { PrepareLayer } from "./PrepareLayer"
import { LayerConfigJson } from "../Json/LayerConfigJson" import { LayerConfigJson } from "../Json/LayerConfigJson"
@ -27,9 +17,9 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
constructor(state: DesugaringContext) { constructor(state: DesugaringContext) {
super( 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 this._state = state
} }
@ -80,23 +70,34 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
(found["tagRenderings"] ?? []).length > 0 (found["tagRenderings"] ?? []).length > 0
) { ) {
context.err( 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 { 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) Utils.Merge(json["override"], found)
layers.push(found) layers.push(found)
} catch (e) { } catch (e) {
context.err( context.err(
`Could not apply an override due to: ${e}.\nThe override is: ${JSON.stringify( `Could not apply an override due to: ${e}.\nThe override is: ${JSON.stringify(
json["override"] json["override"],
)}` )}`,
) )
} }
if (json["hideTagRenderingsWithLabels"]) { if (json["hideTagRenderingsWithLabels"]) {
if(typeof json["hideTagRenderingsWithLabels"] === "string"){ 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"]) const hideLabels: Set<string> = new Set(json["hideTagRenderingsWithLabels"])
// These labels caused at least one deletion // These labels caused at least one deletion
@ -110,9 +111,9 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
usedLabels.add(labels[forbiddenLabel]) usedLabels.add(labels[forbiddenLabel])
context.info( context.info(
"Dropping tagRendering " + "Dropping tagRendering " +
tr["id"] + tr["id"] +
" as it has a forbidden label: " + " as it has a forbidden label: " +
labels[forbiddenLabel] labels[forbiddenLabel],
) )
continue continue
} }
@ -121,7 +122,7 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
if (hideLabels.has(tr["id"])) { if (hideLabels.has(tr["id"])) {
usedLabels.add(tr["id"]) usedLabels.add(tr["id"])
context.info( 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 continue
} }
@ -130,10 +131,10 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
usedLabels.add(tr["group"]) usedLabels.add(tr["group"])
context.info( context.info(
"Dropping tagRendering " + "Dropping tagRendering " +
tr["id"] + tr["id"] +
" as its group `" + " as its group `" +
tr["group"] + tr["group"] +
"` is a forbidden label" "` is a forbidden label",
) )
continue continue
} }
@ -144,8 +145,8 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
if (unused.length > 0) { if (unused.length > 0) {
context.err( 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: " + "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(", ") + 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" "\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 found.tagRenderings = filtered
@ -162,7 +163,7 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
super( super(
"Adds the default layers, namely: " + Constants.added_by_default.join(", "), "Adds the default layers, namely: " + Constants.added_by_default.join(", "),
["layers"], ["layers"],
"AddDefaultLayers" "AddDefaultLayers",
) )
this._state = state this._state = state
} }
@ -186,10 +187,10 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
if (alreadyLoaded.has(v.id)) { if (alreadyLoaded.has(v.id)) {
context.warn( context.warn(
"Layout " + "Layout " +
context + context +
" already has a layer with name " + " already has a layer with name " +
v.id + v.id +
"; skipping inclusion of this builtin layer" "; skipping inclusion of this builtin layer",
) )
continue continue
} }
@ -205,14 +206,14 @@ class AddImportLayers extends DesugaringStep<LayoutConfigJson> {
super( 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)", "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"], ["layers"],
"AddImportLayers" "AddImportLayers",
) )
} }
convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson {
if (!(json.enableNoteImports ?? true)) { if (!(json.enableNoteImports ?? true)) {
context.info( 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 return json
} }
@ -247,7 +248,7 @@ class AddImportLayers extends DesugaringStep<LayoutConfigJson> {
try { try {
const importLayerResult = creator.convert( const importLayerResult = creator.convert(
layer, layer,
context.inOperation(this.name).enter(i1) context.inOperation(this.name).enter(i1),
) )
if (importLayerResult !== undefined) { if (importLayerResult !== undefined) {
json.layers.push(importLayerResult) json.layers.push(importLayerResult)
@ -266,7 +267,7 @@ class AddContextToTranslationsInLayout extends DesugaringStep<LayoutConfigJson>
super( 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", "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"], ["_context"],
"AddContextToTranlationsInLayout" "AddContextToTranlationsInLayout",
) )
} }
@ -281,7 +282,7 @@ class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
super( super(
"Applies 'overrideAll' onto every 'layer'. The 'overrideAll'-field is removed afterwards", "Applies 'overrideAll' onto every 'layer'. The 'overrideAll'-field is removed afterwards",
["overrideAll", "layers"], ["overrideAll", "layers"],
"ApplyOverrideAll" "ApplyOverrideAll",
) )
} }
@ -295,9 +296,29 @@ class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
delete json.overrideAll delete json.overrideAll
const newLayers = [] const newLayers = []
let tagRenderingsPlus = undefined
if (overrideAll["tagRenderings+"] !== undefined) {
tagRenderingsPlus = overrideAll["tagRenderings+"]
delete overrideAll["tagRenderings+"]
}
for (let layer of json.layers) { for (let layer of json.layers) {
layer = Utils.Clone(<LayerConfigJson>layer) layer = Utils.Clone(<LayerConfigJson>layer)
Utils.Merge(overrideAll, 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) newLayers.push(layer)
} }
json.layers = newLayers json.layers = newLayers
@ -317,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. Some layers (e.g. \`all_buildings_and_walls\' or \'streets_with_a_name\') are invisible, so by default, \'force_load\' is set too.
`, `,
["layers"], ["layers"],
"AddDependencyLayersToTheme" "AddDependencyLayersToTheme",
) )
this._state = state this._state = state
} }
@ -325,7 +346,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
private static CalculateDependencies( private static CalculateDependencies(
alreadyLoaded: LayerConfigJson[], alreadyLoaded: LayerConfigJson[],
allKnownLayers: Map<string, LayerConfigJson>, allKnownLayers: Map<string, LayerConfigJson>,
themeId: string themeId: string,
): { config: LayerConfigJson; reason: string }[] { ): { config: LayerConfigJson; reason: string }[] {
const dependenciesToAdd: { config: LayerConfigJson; reason: string }[] = [] const dependenciesToAdd: { config: LayerConfigJson; reason: string }[] = []
const loadedLayerIds: Set<string> = new Set<string>(alreadyLoaded.map((l) => l.id)) const loadedLayerIds: Set<string> = new Set<string>(alreadyLoaded.map((l) => l.id))
@ -348,7 +369,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
for (const layerConfig of alreadyLoaded) { for (const layerConfig of alreadyLoaded) {
try { try {
const layerDeps = DependencyCalculator.getLayerDependencies( const layerDeps = DependencyCalculator.getLayerDependencies(
new LayerConfig(layerConfig, themeId + "(dependencies)") new LayerConfig(layerConfig, themeId + "(dependencies)"),
) )
dependencies.push(...layerDeps) dependencies.push(...layerDeps)
} catch (e) { } catch (e) {
@ -385,10 +406,10 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
if (dep === undefined) { if (dep === undefined) {
const message = [ const message = [
"Loading a dependency failed: layer " + "Loading a dependency failed: layer " +
unmetDependency.neededLayer + unmetDependency.neededLayer +
" is not found, neither as layer of " + " is not found, neither as layer of " +
themeId + themeId +
" nor as builtin layer.", " nor as builtin layer.",
reason, reason,
"Loaded layers are: " + alreadyLoaded.map((l) => l.id).join(","), "Loaded layers are: " + alreadyLoaded.map((l) => l.id).join(","),
] ]
@ -404,7 +425,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
}) })
loadedLayerIds.add(dep.id) loadedLayerIds.add(dep.id)
unmetDependencies = unmetDependencies.filter( unmetDependencies = unmetDependencies.filter(
(d) => d.neededLayer !== unmetDependency.neededLayer (d) => d.neededLayer !== unmetDependency.neededLayer,
) )
} }
} while (unmetDependencies.length > 0) } while (unmetDependencies.length > 0)
@ -425,14 +446,14 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
const dependencies = AddDependencyLayersToTheme.CalculateDependencies( const dependencies = AddDependencyLayersToTheme.CalculateDependencies(
layers, layers,
allKnownLayers, allKnownLayers,
theme.id theme.id,
) )
for (const dependency of dependencies) { for (const dependency of dependencies) {
} }
if (dependencies.length > 0) { if (dependencies.length > 0) {
for (const dependency of dependencies) { for (const dependency of dependencies) {
context.info( context.info(
"Added " + dependency.config.id + " to the theme. " + dependency.reason "Added " + dependency.config.id + " to the theme. " + dependency.reason,
) )
} }
} }
@ -474,7 +495,7 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
super( super(
"Generates a warning if a theme uses an unsubstituted layer", "Generates a warning if a theme uses an unsubstituted layer",
["layers"], ["layers"],
"WarnForUnsubstitutedLayersInTheme" "WarnForUnsubstitutedLayersInTheme",
) )
} }
@ -486,7 +507,7 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
context context
.enter("layers") .enter("layers")
.err( .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 return json
} }
@ -510,10 +531,10 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
context.warn( context.warn(
"The theme " + "The theme " +
json.id + json.id +
" has an inline layer: " + " has an inline layer: " +
layer["id"] + layer["id"] +
". This is discouraged." ". This is discouraged.",
) )
} }
return json return json
@ -522,11 +543,12 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
export class PrepareTheme extends Fuse<LayoutConfigJson> { export class PrepareTheme extends Fuse<LayoutConfigJson> {
private state: DesugaringContext private state: DesugaringContext
constructor( constructor(
state: DesugaringContext, state: DesugaringContext,
options?: { options?: {
skipDefaultLayers: false | boolean skipDefaultLayers: false | boolean
} },
) { ) {
super( super(
"Fully prepares and expands a theme", "Fully prepares and expands a theme",
@ -538,7 +560,7 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
new SetDefault("socialImage", "assets/SocialImage.png", true), new SetDefault("socialImage", "assets/SocialImage.png", true),
// We expand all tagrenderings first... // We expand all tagrenderings first...
new On("layers", new Each(new PrepareLayer(state))), new On("layers", new Each(new PrepareLayer(state))),
// Then we apply the override all // Then we apply the override all. Note that it'll cheat with tagRenderings+
new ApplyOverrideAll(), new ApplyOverrideAll(),
// And then we prepare all the layers _again_ in case that an override all contained unexpanded tagrenderings! // 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))), new On("layers", new Each(new PrepareLayer(state))),
@ -546,7 +568,7 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
? new Pass("AddDefaultLayers is disabled due to the set flag") ? new Pass("AddDefaultLayers is disabled due to the set flag")
: new AddDefaultLayers(state), : new AddDefaultLayers(state),
new AddDependencyLayersToTheme(state), new AddDependencyLayersToTheme(state),
new AddImportLayers() new AddImportLayers(),
) )
this.state = state this.state = state
} }
@ -561,13 +583,13 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
const needsNodeDatabase = result.layers?.some((l: LayerConfigJson) => const needsNodeDatabase = result.layers?.some((l: LayerConfigJson) =>
l.tagRenderings?.some((tr) => l.tagRenderings?.some((tr) =>
ValidationUtils.getSpecialVisualisations(<any>tr)?.some( ValidationUtils.getSpecialVisualisations(<any>tr)?.some(
(special) => special.needsNodeDatabase (special) => special.needsNodeDatabase,
) ),
) ),
) )
if (needsNodeDatabase) { if (needsNodeDatabase) {
context.info( 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 result.enableNodeDatabase = true
} }