chore: automated housekeeping...

This commit is contained in:
Pieter Vander Vennet 2025-01-18 00:30:06 +01:00
parent d7509c8d6f
commit 66c27cbad4
127 changed files with 6557 additions and 2698 deletions

View file

@ -15,47 +15,73 @@ import { FlatTag, OptimizedTag, TagsFilterClosed } from "../../../Logic/Tags/Tag
import { TagsFilter } from "../../../Logic/Tags/TagsFilter"
import { And } from "../../../Logic/Tags/And"
export class PruneFilters extends DesugaringStep<LayerConfigJson>{
export class PruneFilters extends DesugaringStep<LayerConfigJson> {
constructor() {
super("Removes all filters which are impossible, e.g. because they conflict with the base tags", ["filter"],"PruneFilters")
super(
"Removes all filters which are impossible, e.g. because they conflict with the base tags",
["filter"],
"PruneFilters"
)
}
private prune(sourceTags:FlatTag, filter: FilterConfigJson, context: ConversionContext): FilterConfigJson{
if(!filter.strict){
private prune(
sourceTags: FlatTag,
filter: FilterConfigJson,
context: ConversionContext
): FilterConfigJson {
if (!filter.strict) {
return filter
}
const countBefore = filter.options.length
const newOptions: FilterConfigOptionJson[] = filter.options.filter(option => {
if(!option.osmTags){
return true
}
const condition = <OptimizedTag & TagsFilterClosed> TagUtils.Tag(option.osmTags).optimize()
return condition.shadows(sourceTags);
}).map(option => {
if(!option.osmTags){
return option
}
let basetags = TagUtils.Tag(option.osmTags)
return {...option, osmTags: (<TagsFilter>TagUtils.removeKnownParts(basetags ,sourceTags)).asJson()}
})
const newOptions: FilterConfigOptionJson[] = filter.options
.filter((option) => {
if (!option.osmTags) {
return true
}
const condition = <OptimizedTag & TagsFilterClosed>(
TagUtils.Tag(option.osmTags).optimize()
)
return condition.shadows(sourceTags)
})
.map((option) => {
if (!option.osmTags) {
return option
}
let basetags = TagUtils.Tag(option.osmTags)
return {
...option,
osmTags: (<TagsFilter>TagUtils.removeKnownParts(basetags, sourceTags)).asJson(),
}
})
const countAfter = newOptions.length
if(countAfter !== countBefore){
context.enters("filter", filter.id ).info("Pruned "+(countBefore-countAfter)+" options away from filter (out of "+countBefore+")")
if (countAfter !== countBefore) {
context
.enters("filter", filter.id)
.info(
"Pruned " +
(countBefore - countAfter) +
" options away from filter (out of " +
countBefore +
")"
)
}
return {...filter, options: newOptions, strict: undefined}
return { ...filter, options: newOptions, strict: undefined }
}
public convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson {
if(!Array.isArray(json.filter) || typeof json.source === "string"){
if (!Array.isArray(json.filter) || typeof json.source === "string") {
return json
}
if(!json.source["osmTags"]){
if (!json.source["osmTags"]) {
return json
}
const sourceTags = TagUtils.Tag(json.source["osmTags"])
return {...json, filter: json.filter?.map(obj => this.prune(sourceTags, <FilterConfigJson> obj, context))}
return {
...json,
filter: json.filter?.map((obj) =>
this.prune(sourceTags, <FilterConfigJson>obj, context)
),
}
}
}
export class ExpandFilter extends DesugaringStep<LayerConfigJson> {
@ -69,7 +95,7 @@ export class ExpandFilter extends DesugaringStep<LayerConfigJson> {
"If the string is formatted 'layername.filtername, it will be looked up into that layer instead. Note that pruning should still be done",
].join(" "),
["filter"],
"ExpandFilter",
"ExpandFilter"
)
this._state = state
}
@ -84,11 +110,11 @@ export class ExpandFilter extends DesugaringStep<LayerConfigJson> {
public static buildFilterFromTagRendering(
tr: TagRenderingConfigJson,
context: ConversionContext,
context: ConversionContext
): FilterConfigJson {
if (!(tr.mappings?.length >= 1)) {
context.err(
"Found a matching tagRendering to base a filter on, but this tagRendering does not contain any mappings",
"Found a matching tagRendering to base a filter on, but this tagRendering does not contain any mappings"
)
}
const qtr = <QuestionableTagRenderingConfigJson>tr
@ -103,7 +129,7 @@ export class ExpandFilter extends DesugaringStep<LayerConfigJson> {
if (qtr.multiAnswer && osmTags instanceof Tag) {
osmTags = new RegexTag(
osmTags.key,
new RegExp("^(.+;)?" + osmTags.value + "(;.+)$", "is"),
new RegExp("^(.+;)?" + osmTags.value + "(;.+)$", "is")
)
}
if (mapping.alsoShowIf) {
@ -161,7 +187,7 @@ export class ExpandFilter extends DesugaringStep<LayerConfigJson> {
if (matchingTr) {
const filter = ExpandFilter.buildFilterFromTagRendering(
matchingTr,
context.enters("filter", i),
context.enters("filter", i)
)
newFilters.push(filter)
continue
@ -175,7 +201,7 @@ export class ExpandFilter extends DesugaringStep<LayerConfigJson> {
const split = filter.split(".")
if (split.length > 2) {
context.err(
"invalid filter name: " + filter + ", expected `layername.filterid`",
"invalid filter name: " + filter + ", expected `layername.filterid`"
)
}
const layer = this._state.sharedLayers.get(split[0])
@ -184,7 +210,7 @@ export class ExpandFilter extends DesugaringStep<LayerConfigJson> {
}
const expectedId = split[1]
const expandedFilter = (<(FilterConfigJson | string)[]>layer.filter).find(
(f) => typeof f !== "string" && f.id === expectedId,
(f) => typeof f !== "string" && f.id === expectedId
)
if (expandedFilter === undefined) {
context.err("Did not find filter with name " + filter)
@ -199,15 +225,15 @@ export class ExpandFilter extends DesugaringStep<LayerConfigJson> {
const suggestions = Utils.sortedByLevenshteinDistance(
filter,
Array.from(ExpandFilter.predefinedFilters.keys()),
(t) => t,
(t) => t
)
context
.enter(filter)
.err(
"While searching for predefined filter " +
filter +
": this filter is not found. Perhaps you meant one of: " +
suggestions,
filter +
": this filter is not found. Perhaps you meant one of: " +
suggestions
)
}
newFilters.push(found)

View file

@ -11,9 +11,9 @@ export class ExpandTagRendering extends Conversion<
| string
| TagRenderingConfigJson
| {
builtin: string | string[]
override: any
},
builtin: string | string[]
override: any
},
TagRenderingConfigJson[]
> {
private readonly _state: DesugaringContext
@ -35,12 +35,12 @@ export class ExpandTagRendering extends Conversion<
noHardcodedStrings?: false | boolean
// If set, a question will be added to the 'sharedTagRenderings'. Should only be used for 'questions.json'
addToContext?: false | boolean
},
}
) {
super(
"Converts a tagRenderingSpec into the full tagRendering, e.g. by substituting the tagRendering by the shared-question and reusing the builtins",
[],
"ExpandTagRendering",
"ExpandTagRendering"
)
this._state = state
this._self = self
@ -60,10 +60,11 @@ export class ExpandTagRendering extends Conversion<
public convert(
spec: string | any,
ctx: ConversionContext,
ctx: ConversionContext
): QuestionableTagRenderingConfigJson[] {
const trs = this.convertOnce(spec, ctx)
?.map(tr => this.pruneMappings<TagRenderingConfigJson & { id: string }>(tr, ctx))
const trs = this.convertOnce(spec, ctx)?.map((tr) =>
this.pruneMappings<TagRenderingConfigJson & { id: string }>(tr, ctx)
)
if (!Array.isArray(trs)) {
ctx.err("Result of lookup for " + spec + " is not iterable; got " + trs)
return undefined
@ -71,8 +72,9 @@ export class ExpandTagRendering extends Conversion<
const result = []
for (const tr of trs) {
if (typeof tr === "string" || tr["builtin"] !== undefined) {
const stable = this.convert(tr, ctx.inOperation("recursive_resolve"))
.map(tr => this.pruneMappings(tr, ctx))
const stable = this.convert(tr, ctx.inOperation("recursive_resolve")).map((tr) =>
this.pruneMappings(tr, ctx)
)
result.push(...stable)
if (this._options?.addToContext) {
for (const tr of stable) {
@ -90,39 +92,47 @@ export class ExpandTagRendering extends Conversion<
return result
}
private pruneMappings<T extends (TagRenderingConfigJson & {
id: string
})>(tagRendering: T, ctx: ConversionContext): T {
private pruneMappings<
T extends TagRenderingConfigJson & {
id: string
}
>(tagRendering: T, ctx: ConversionContext): T {
if (!tagRendering["strict"]) {
return tagRendering
}
if(!this._self.source["osmTags"]){
if (!this._self.source["osmTags"]) {
return tagRendering
}
ctx.inOperation("expandTagRendering:pruning").enters(tagRendering.id)
.info(`PRUNING! Tagrendering to prune: ${tagRendering.id} in the context of layer ${this._self.id} Sourcetags: ${this._self.source["osmTags"]}`)
ctx.inOperation("expandTagRendering:pruning")
.enters(tagRendering.id)
.info(
`PRUNING! Tagrendering to prune: ${tagRendering.id} in the context of layer ${this._self.id} Sourcetags: ${this._self.source["osmTags"]}`
)
const before = tagRendering.mappings?.length ?? 0
const alwaysTags = TagUtils.Tag(this._self.source["osmTags"])
const newMappings = tagRendering.mappings?.filter(mapping => {
const condition = TagUtils.Tag(mapping.if)
return condition.shadows(alwaysTags);
}).map(mapping => {
const newIf = TagUtils.removeKnownParts(
TagUtils.Tag(mapping.if), alwaysTags)
if (typeof newIf === "boolean") {
throw "Invalid removeKnownParts"
}
return {
...mapping,
if: newIf.asJson(),
}
})
const newMappings = tagRendering.mappings
?.filter((mapping) => {
const condition = TagUtils.Tag(mapping.if)
return condition.shadows(alwaysTags)
})
.map((mapping) => {
const newIf = TagUtils.removeKnownParts(TagUtils.Tag(mapping.if), alwaysTags)
if (typeof newIf === "boolean") {
throw "Invalid removeKnownParts"
}
return {
...mapping,
if: newIf.asJson(),
}
})
const after = newMappings?.length ?? 0
if (before - after > 0) {
ctx.info(`Pruned mappings for ${tagRendering.id}, from ${before} to ${after} (removed ${before - after})`)
ctx.info(
`Pruned mappings for ${tagRendering.id}, from ${before} to ${after} (removed ${
before - after
})`
)
}
const tr = {
...tagRendering,
@ -132,7 +142,10 @@ export class ExpandTagRendering extends Conversion<
return tr
}
private lookup(name: string, ctx: ConversionContext): (TagRenderingConfigJson & { id: string })[] | undefined {
private lookup(
name: string,
ctx: ConversionContext
): (TagRenderingConfigJson & { id: string })[] | undefined {
const direct = this.directLookup(name)
if (direct === undefined) {
@ -202,9 +215,11 @@ export class ExpandTagRendering extends Conversion<
matchingTrs = layerTrs.filter((tr) => tr["id"] === id || tr["labels"]?.indexOf(id) >= 0)
}
const contextWriter = new AddContextToTranslations<TagRenderingConfigJson & { id: string }>("layers:")
const contextWriter = new AddContextToTranslations<TagRenderingConfigJson & { id: string }>(
"layers:"
)
for (let i = 0; i < matchingTrs.length; i++) {
let found: (TagRenderingConfigJson & { id: string }) = Utils.Clone(matchingTrs[i])
let found: TagRenderingConfigJson & { id: string } = Utils.Clone(matchingTrs[i])
if (this._options?.applyCondition) {
// The matched tagRenderings are 'stolen' from another layer. This means that they must match the layer condition before being shown
if (typeof layer.source !== "string") {
@ -220,8 +235,8 @@ export class ExpandTagRendering extends Conversion<
found,
ConversionContext.construct(
[layer.id, "tagRenderings", found["id"]],
["AddContextToTranslations"],
),
["AddContextToTranslations"]
)
)
matchingTrs[i] = found
}
@ -232,7 +247,10 @@ export class ExpandTagRendering extends Conversion<
return undefined
}
private convertOnce(tr: string | any, ctx: ConversionContext): (TagRenderingConfigJson & { id: string })[] {
private convertOnce(
tr: string | any,
ctx: ConversionContext
): (TagRenderingConfigJson & { id: string })[] {
const state = this._state
if (typeof tr === "string") {
@ -250,17 +268,17 @@ export class ExpandTagRendering extends Conversion<
ctx.warn(
`A literal rendering was detected: ${tr}
Did you perhaps forgot to add a layer name as 'layername.${tr}'? ` +
Array.from(state.sharedLayers.keys()).join(", "),
Array.from(state.sharedLayers.keys()).join(", ")
)
}
if (this._options?.noHardcodedStrings && this._state?.sharedLayers?.size > 0) {
ctx.err(
"Detected an invocation to a builtin tagRendering, but this tagrendering was not found: " +
tr +
" \n Did you perhaps forget to add the layer as prefix, such as `icons." +
tr +
"`? ",
tr +
" \n Did you perhaps forget to add the layer as prefix, such as `icons." +
tr +
"`? "
)
}
@ -293,9 +311,9 @@ export class ExpandTagRendering extends Conversion<
}
ctx.err(
"An object calling a builtin can only have keys `builtin` or `override`, but a key with name `" +
key +
"` was found. This won't be picked up! The full object is: " +
JSON.stringify(tr),
key +
"` was found. This won't be picked up! The full object is: " +
JSON.stringify(tr)
)
}
@ -317,39 +335,39 @@ export class ExpandTagRendering extends Conversion<
const candidates = Utils.sortedByLevenshteinDistance(
layerName,
Utils.NoNull(Array.from(state.sharedLayers.keys())),
(s) => s,
(s) => s
)
if (state.sharedLayers.size === 0) {
ctx.warn(
"BOOTSTRAPPING. Rerun generate layeroverview. While reusing tagrendering: " +
name +
": layer " +
layerName +
" not found for now, but ignoring as this is a bootstrapping run. ",
name +
": layer " +
layerName +
" not found for now, but ignoring as this is a bootstrapping run. "
)
} else {
ctx.err(
": While reusing tagrendering: " +
name +
": layer " +
layerName +
" not found. Maybe you meant one of " +
candidates.slice(0, 3).join(", "),
name +
": layer " +
layerName +
" not found. Maybe you meant one of " +
candidates.slice(0, 3).join(", ")
)
}
continue
}
candidates = Utils.NoNull(layer.tagRenderings.map((tr) => tr["id"])).map(
(id) => layerName + "." + id,
(id) => layerName + "." + id
)
}
candidates = Utils.sortedByLevenshteinDistance(name, candidates, (i) => i)
ctx.err(
"The tagRendering with identifier " +
name +
" was not found.\n\tDid you mean one of " +
candidates.join(", ") +
"?\n(Hint: did you add a new label and are you trying to use this label at the same time? Run 'reset:layeroverview' first",
name +
" was not found.\n\tDid you mean one of " +
candidates.join(", ") +
"?\n(Hint: did you add a new label and are you trying to use this label at the same time? Run 'reset:layeroverview' first"
)
continue
}

View file

@ -1,6 +1,18 @@
import { Concat, DesugaringContext, DesugaringStep, Each, FirstOf, Fuse, On, SetDefault } from "./Conversion"
import {
Concat,
DesugaringContext,
DesugaringStep,
Each,
FirstOf,
Fuse,
On,
SetDefault,
} from "./Conversion"
import { LayerConfigJson } from "../Json/LayerConfigJson"
import { MinimalTagRenderingConfigJson, TagRenderingConfigJson } from "../Json/TagRenderingConfigJson"
import {
MinimalTagRenderingConfigJson,
TagRenderingConfigJson,
} from "../Json/TagRenderingConfigJson"
import { Utils } from "../../../Utils"
import RewritableConfigJson from "../Json/RewritableConfigJson"
import SpecialVisualizations from "../../../UI/SpecialVisualizations"
@ -695,7 +707,7 @@ class PreparePointRendering extends Fuse<PointRenderingConfigJson> {
constructor(state: DesugaringContext, layer: LayerConfigJson) {
super(
"Prepares point renderings by expanding 'icon' and 'iconBadges'." +
" A tagRendering from the host tagRenderings will be substituted in",
" A tagRendering from the host tagRenderings will be substituted in",
new On(
"marker",
new Each(
@ -751,19 +763,21 @@ class ExpandMarkerRenderings extends DesugaringStep<IconConfigJson> {
}
convert(json: IconConfigJson, context: ConversionContext): IconConfigJson {
const expander = new ExpandTagRendering(this._state, this._layer, {applyCondition: false})
const expander = new ExpandTagRendering(this._state, this._layer, { applyCondition: false })
const result: IconConfigJson = { icon: undefined, color: undefined }
if (json.icon && json.icon["builtin"]) {
result.icon = <MinimalTagRenderingConfigJson>(
expander.convert(<any>json.icon, context.enter("icon"))[0]
) ?? json.icon
result.icon =
<MinimalTagRenderingConfigJson>(
expander.convert(<any>json.icon, context.enter("icon"))[0]
) ?? json.icon
} else {
result.icon = json.icon
}
if (json.color && json.color["builtin"]) {
result.color = <MinimalTagRenderingConfigJson>(
expander.convert(<any>json.color, context.enter("color"))[0]
) ?? json.color
result.color =
<MinimalTagRenderingConfigJson>(
expander.convert(<any>json.color, context.enter("color"))[0]
) ?? json.color
} else {
result.color = json.color
}
@ -1002,7 +1016,7 @@ export class PrepareLayer extends Fuse<LayerConfigJson> {
}
convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson {
if(json === undefined || json === null){
if (json === undefined || json === null) {
throw "Error: prepareLayer got null"
}
return super.convert(json, context)

View file

@ -112,7 +112,7 @@ export class DoesImageExist extends DesugaringStep<string> {
if (!this._knownImagePaths.has(image)) {
if (this.doesPathExist === undefined || image.indexOf("nsi/logos/") >= 0) {
// pass
} else if (!this.doesPathExist(image) ) {
} else if (!this.doesPathExist(image)) {
context.err(
`Image with path ${image} does not exist.\n Check for typo's and missing directories in the path. `
)

View file

@ -78,10 +78,11 @@ export default class LayerConfig extends WithContextLoader {
*/
private readonly _basedOn: string | undefined
constructor(json: LayerConfigJson,
context?: string,
official: boolean = true,
allLayers?: LayerConfigJson[],
constructor(
json: LayerConfigJson,
context?: string,
official: boolean = true,
allLayers?: LayerConfigJson[]
) {
context = context + "." + json?.id
const translationContext = "layers:" + json.id
@ -113,7 +114,7 @@ export default class LayerConfig extends WithContextLoader {
mercatorCrs: json.source["mercatorCrs"],
idKey: json.source["idKey"],
},
json.id,
json.id
)
}
@ -133,7 +134,7 @@ export default class LayerConfig extends WithContextLoader {
if (json.calculatedTags !== undefined) {
if (!official) {
console.warn(
`Unofficial theme ${this.id} with custom javascript! This is a security risk`,
`Unofficial theme ${this.id} with custom javascript! This is a security risk`
)
}
this.calculatedTags = []
@ -203,7 +204,7 @@ export default class LayerConfig extends WithContextLoader {
tags: pr.tags.map((t) => TagUtils.SimpleTag(t)),
description: Translations.T(
pr.description,
`${translationContext}.presets.${i}.description`,
`${translationContext}.presets.${i}.description`
),
preciseInput: preciseInput,
exampleImages: pr.exampleImages,
@ -217,7 +218,7 @@ export default class LayerConfig extends WithContextLoader {
if (json.lineRendering) {
this.lineRendering = Utils.NoNull(json.lineRendering).map(
(r, i) => new LineRenderingConfig(r, `${context}[${i}]`),
(r, i) => new LineRenderingConfig(r, `${context}[${i}]`)
)
} else {
this.lineRendering = []
@ -225,7 +226,7 @@ export default class LayerConfig extends WithContextLoader {
if (json.pointRendering) {
this.mapRendering = Utils.NoNull(json.pointRendering).map(
(r, i) => new PointRenderingConfig(r, `${context}[${i}](${this.id})`),
(r, i) => new PointRenderingConfig(r, `${context}[${i}](${this.id})`)
)
} else {
this.mapRendering = []
@ -237,7 +238,7 @@ export default class LayerConfig extends WithContextLoader {
r.location.has("centroid") ||
r.location.has("projected_centerpoint") ||
r.location.has("start") ||
r.location.has("end"),
r.location.has("end")
)
if (
@ -259,7 +260,7 @@ export default class LayerConfig extends WithContextLoader {
Constants.priviliged_layers.indexOf(<any>this.id) < 0 &&
this.source !== null /*library layer*/ &&
!this.source?.geojsonSource?.startsWith(
"https://api.openstreetmap.org/api/0.6/notes.json",
"https://api.openstreetmap.org/api/0.6/notes.json"
)
) {
throw (
@ -278,7 +279,7 @@ export default class LayerConfig extends WithContextLoader {
typeof tr !== "string" &&
tr["builtin"] === undefined &&
tr["id"] === undefined &&
tr["rewrite"] === undefined,
tr["rewrite"] === undefined
) ?? []
if (missingIds?.length > 0 && official) {
console.error("Some tagRenderings of", this.id, "are missing an id:", missingIds)
@ -289,8 +290,8 @@ export default class LayerConfig extends WithContextLoader {
(tr, i) =>
new TagRenderingConfig(
<QuestionableTagRenderingConfigJson>tr,
this.id + ".tagRenderings[" + i + "]",
),
this.id + ".tagRenderings[" + i + "]"
)
)
if (json.units !== undefined && !Array.isArray(json.units)) {
throw (
@ -300,19 +301,15 @@ export default class LayerConfig extends WithContextLoader {
)
}
this.units = (json.units ?? []).flatMap((unitJson, i) =>
Unit.fromJson(unitJson, this.tagRenderings, `${context}.unit[${i}]`),
Unit.fromJson(unitJson, this.tagRenderings, `${context}.unit[${i}]`)
)
{
let filter = json.filter
while (
filter !== undefined &&
filter !== null &&
filter["sameAs"] !== undefined
) {
while (filter !== undefined && filter !== null && filter["sameAs"] !== undefined) {
const targetLayerName = filter["sameAs"]
this.filterIsSameAs = targetLayerName
const targetLayer = allLayers?.find(l => l.id === targetLayerName)
const targetLayer = allLayers?.find((l) => l.id === targetLayerName)
if (allLayers && !targetLayer) {
throw "Target layer " + targetLayerName + " not found in this theme"
}
@ -373,7 +370,7 @@ export default class LayerConfig extends WithContextLoader {
}
this.popupInFloatover = json.popupInFloatover ?? false
this.baseTags = TagUtils.changeAsProperties(
this.source?.osmTags?.asChange({ id: "node/-1" }) ?? [{ k: "id", v: "node/-1" }],
this.source?.osmTags?.asChange({ id: "node/-1" }) ?? [{ k: "id", v: "node/-1" }]
)
}
@ -393,7 +390,7 @@ export default class LayerConfig extends WithContextLoader {
neededLayer: string
}[] = [],
addedByDefault = false,
canBeIncluded = true,
canBeIncluded = true
): string {
const extraProps: string[] = []
extraProps.push("This layer is shown at zoomlevel **" + this.minzoom + "** and higher")
@ -401,32 +398,32 @@ export default class LayerConfig extends WithContextLoader {
if (canBeIncluded) {
if (addedByDefault) {
extraProps.push(
"**This layer is included automatically in every theme. This layer might contain no points**",
"**This layer is included automatically in every theme. This layer might contain no points**"
)
}
if (this.shownByDefault === false) {
extraProps.push(
"This layer is not visible by default and must be enabled in the filter by the user. ",
"This layer is not visible by default and must be enabled in the filter by the user. "
)
}
if (this.title === undefined) {
extraProps.push(
"Elements don't have a title set and cannot be toggled nor will they show up in the dashboard. If you import this layer in your theme, override `title` to make this toggleable.",
"Elements don't have a title set and cannot be toggled nor will they show up in the dashboard. If you import this layer in your theme, override `title` to make this toggleable."
)
}
if (this.name === undefined && this.shownByDefault === false) {
extraProps.push(
"This layer is not visible by default and the visibility cannot be toggled, effectively resulting in a fully hidden layer. This can be useful, e.g. to calculate some metatags. If you want to render this layer (e.g. for debugging), enable it by setting the URL-parameter layer-<id>=true",
"This layer is not visible by default and the visibility cannot be toggled, effectively resulting in a fully hidden layer. This can be useful, e.g. to calculate some metatags. If you want to render this layer (e.g. for debugging), enable it by setting the URL-parameter layer-<id>=true"
)
}
if (this.name === undefined) {
extraProps.push(
"Not visible in the layer selection by default. If you want to make this layer toggable, override `name`",
"Not visible in the layer selection by default. If you want to make this layer toggable, override `name`"
)
}
if (this.mapRendering.length === 0) {
extraProps.push(
"Not rendered on the map by default. If you want to rendering this on the map, override `mapRenderings`",
"Not rendered on the map by default. If you want to rendering this on the map, override `mapRenderings`"
)
}
@ -436,12 +433,12 @@ export default class LayerConfig extends WithContextLoader {
"<img src='../warning.svg' height='1rem'/>",
"This layer is loaded from an external source, namely ",
"`" + this.source.geojsonSource + "`",
].join("\n\n"),
].join("\n\n")
)
}
} else {
extraProps.push(
"This layer can **not** be included in a theme. It is solely used by [special renderings](SpecialRenderings.md) showing a minimap with custom data.",
"This layer can **not** be included in a theme. It is solely used by [special renderings](SpecialRenderings.md) showing a minimap with custom data."
)
}
@ -451,7 +448,7 @@ export default class LayerConfig extends WithContextLoader {
usingLayer = [
"## Themes using this layer",
MarkdownUtils.list(
(usedInThemes ?? []).map((id) => `[${id}](https://mapcomplete.org/${id})`),
(usedInThemes ?? []).map((id) => `[${id}](https://mapcomplete.org/${id})`)
),
]
} else if (this.source !== null) {
@ -467,7 +464,7 @@ export default class LayerConfig extends WithContextLoader {
" into the layout as it depends on it: ",
dep.reason,
"(" + dep.context + ")",
].join(" "),
].join(" ")
)
}
@ -494,7 +491,7 @@ export default class LayerConfig extends WithContextLoader {
new And(preset.tags).asHumanString(true) +
snaps
)
}),
})
),
]
}
@ -502,8 +499,8 @@ export default class LayerConfig extends WithContextLoader {
for (const revDep of Utils.Dedup(layerIsNeededBy?.get(this.id) ?? [])) {
extraProps.push(
["This layer is needed as dependency for layer", `[${revDep}](#${revDep})`].join(
" ",
),
" "
)
)
}
@ -514,10 +511,10 @@ export default class LayerConfig extends WithContextLoader {
.filter((values) => values.key !== "id")
.map((values) => {
const embedded: string[] = values.values?.map((v) =>
Link.OsmWiki(values.key, v, true).SetClass("mr-2").AsMarkdown(),
Link.OsmWiki(values.key, v, true).SetClass("mr-2").AsMarkdown()
) ?? ["_no preset options defined, or no values in them_"]
const statistics = `https://taghistory.raifer.tech/?#***/${encodeURIComponent(
values.key,
values.key
)}/`
const tagInfo = `https://taginfo.openstreetmap.org/keys/${values.key}#values`
return [
@ -532,7 +529,7 @@ export default class LayerConfig extends WithContextLoader {
: `[${values.type}](../SpecialInputElements.md#${values.type})`,
embedded.join(" "),
]
}),
})
)
let quickOverview: string[] = []
@ -542,7 +539,7 @@ export default class LayerConfig extends WithContextLoader {
"this quick overview is incomplete",
MarkdownUtils.table(
["attribute", "type", "values which are supported by this layer"],
tableRows,
tableRows
),
]
}
@ -576,19 +573,19 @@ export default class LayerConfig extends WithContextLoader {
const parts = neededTags["and"]
tagsDescription.push(
"Elements must match **all** of the following expressions:",
parts.map((p, i) => i + ". " + p.asHumanString(true, false, {})).join("\n"),
parts.map((p, i) => i + ". " + p.asHumanString(true, false, {})).join("\n")
)
} else if (neededTags["or"]) {
const parts = neededTags["or"]
tagsDescription.push(
"Elements must match **any** of the following expressions:",
parts.map((p) => " - " + p.asHumanString(true, false, {})).join("\n"),
parts.map((p) => " - " + p.asHumanString(true, false, {})).join("\n")
)
} else {
tagsDescription.push(
"Elements must match the expression **" +
neededTags.asHumanString(true, false, {}) +
"**",
neededTags.asHumanString(true, false, {}) +
"**"
)
}

View file

@ -99,7 +99,7 @@ export default class ThemeConfig implements ThemeInformation {
options?: {
definedAtUrl?: string
definitionRaw?: string
},
}
) {
if (json === undefined) {
throw "Cannot construct a layout config, the parameter 'json' is undefined"
@ -130,7 +130,7 @@ export default class ThemeConfig implements ThemeInformation {
throw `The title of a theme should always be a translation, as it sets the corresponding languages (${context}.title). The themenID is ${
this.id
}; the offending object is ${JSON.stringify(
json.title,
json.title
)} which is a ${typeof json.title})`
}
if (this.language.length == 0) {
@ -184,8 +184,8 @@ export default class ThemeConfig implements ThemeInformation {
<LayerConfigJson>lyrJson,
json.id + ".layers." + lyrJson["id"],
official,
<LayerConfigJson[]>json.layers,
),
<LayerConfigJson[]>json.layers
)
)
this.extraLink = new ExtraLinkConfig(
@ -195,7 +195,7 @@ export default class ThemeConfig implements ThemeInformation {
newTab: true,
requirements: ["iframe", "no-welcome-message"],
},
context + ".extraLink",
context + ".extraLink"
)
this.hideFromOverview = json.hideFromOverview ?? false
@ -301,7 +301,7 @@ export default class ThemeConfig implements ThemeInformation {
return false
}
return o instanceof Translation
},
}
)
return { untranslated, total }
@ -309,7 +309,7 @@ export default class ThemeConfig implements ThemeInformation {
public getMatchingLayer(
tags: Record<string, string>,
blacklistLayers?: Set<string>,
blacklistLayers?: Set<string>
): LayerConfig | undefined {
if (tags === undefined) {
return undefined
@ -338,7 +338,7 @@ export default class ThemeConfig implements ThemeInformation {
"Fallthrough: could not find the appropriate layer for an object with tags",
tags,
"within layout",
this,
this
)
return undefined
}