Themes: automatically derive source from presets if no source is given
This commit is contained in:
parent
257a35d219
commit
8e18864daa
6 changed files with 243 additions and 184 deletions
|
@ -81,15 +81,16 @@ class ParseLayer extends Conversion<
|
|||
}
|
||||
const fixed = this._prepareLayer.convert(parsed, context.inOperation("PrepareLayer"))
|
||||
|
||||
if (!fixed.source) {
|
||||
context.enter("source").err("No source is configured")
|
||||
if (!fixed.source && fixed.presets?.length < 1) {
|
||||
context.enter("source").err("No source is configured. (Tags might be automatically derived if presets are given)")
|
||||
return undefined
|
||||
}
|
||||
|
||||
if (
|
||||
fixed.source &&
|
||||
typeof fixed.source !== "string" &&
|
||||
fixed.source["osmTags"] &&
|
||||
fixed.source["osmTags"]["and"] === undefined
|
||||
fixed.source?.["osmTags"] &&
|
||||
fixed.source?.["osmTags"]["and"] === undefined
|
||||
) {
|
||||
fixed.source["osmTags"] = { and: [fixed.source["osmTags"]] }
|
||||
}
|
||||
|
|
|
@ -25,6 +25,10 @@ export class UpdateLegacyLayer extends DesugaringStep<
|
|||
context = context.enter(json.id)
|
||||
let config = { ...json }
|
||||
|
||||
if(config["credits"] === "Not logged in"){
|
||||
delete config["credits"]
|
||||
}
|
||||
|
||||
if (config["overpassTags"]) {
|
||||
config.source = config.source ?? {
|
||||
osmTags: config["overpassTags"],
|
||||
|
@ -142,9 +146,11 @@ export class UpdateLegacyLayer extends DesugaringStep<
|
|||
delete config["wayHandling"]
|
||||
delete config["hideUnderlayingFeaturesMinPercentage"]
|
||||
const src = config.source
|
||||
delete src["isOsmCache"]
|
||||
delete src["maxCacheAge"]
|
||||
delete src["widenFactor"]
|
||||
if(src){
|
||||
delete src["isOsmCache"]
|
||||
delete src["maxCacheAge"]
|
||||
delete src["widenFactor"]
|
||||
}
|
||||
|
||||
for (const mapRenderingElement of config["mapRendering"] ?? []) {
|
||||
if (mapRenderingElement["iconOverlays"] !== undefined) {
|
||||
|
|
|
@ -32,6 +32,7 @@ import { ConfigMeta } from "../../../UI/Studio/configMeta"
|
|||
import LineRenderingConfigJson from "../Json/LineRenderingConfigJson"
|
||||
import { ConversionContext } from "./ConversionContext"
|
||||
import { ExpandRewrite } from "./ExpandRewrite"
|
||||
import { TagUtils } from "../../../Logic/Tags/TagUtils"
|
||||
|
||||
class ExpandFilter extends DesugaringStep<LayerConfigJson> {
|
||||
private static readonly predefinedFilters = ExpandFilter.load_filters()
|
||||
|
@ -41,7 +42,7 @@ class ExpandFilter extends DesugaringStep<LayerConfigJson> {
|
|||
super(
|
||||
"Expands filters: replaces a shorthand by the value found in 'filters.json'. If the string is formatted 'layername.filtername, it will be looked up into that layer instead",
|
||||
["filter"],
|
||||
"ExpandFilter"
|
||||
"ExpandFilter",
|
||||
)
|
||||
this._state = state
|
||||
}
|
||||
|
@ -111,7 +112,7 @@ class ExpandFilter extends DesugaringStep<LayerConfigJson> {
|
|||
context
|
||||
.enters("filter", i)
|
||||
.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 options = matchingTr.mappings.map((mapping) => ({
|
||||
|
@ -136,7 +137,7 @@ 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])
|
||||
|
@ -145,7 +146,7 @@ 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)
|
||||
|
@ -163,15 +164,15 @@ 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)
|
||||
|
@ -184,9 +185,9 @@ class ExpandTagRendering extends Conversion<
|
|||
| string
|
||||
| TagRenderingConfigJson
|
||||
| {
|
||||
builtin: string | string[]
|
||||
override: any
|
||||
},
|
||||
builtin: string | string[]
|
||||
override: any
|
||||
},
|
||||
TagRenderingConfigJson[]
|
||||
> {
|
||||
private readonly _state: DesugaringContext
|
||||
|
@ -208,12 +209,12 @@ 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
|
||||
|
@ -233,7 +234,7 @@ class ExpandTagRendering extends Conversion<
|
|||
|
||||
public convert(
|
||||
spec: string | any,
|
||||
ctx: ConversionContext
|
||||
ctx: ConversionContext,
|
||||
): QuestionableTagRenderingConfigJson[] {
|
||||
const trs = this.convertOnce(spec, ctx)
|
||||
|
||||
|
@ -346,8 +347,8 @@ class ExpandTagRendering extends Conversion<
|
|||
found,
|
||||
ConversionContext.construct(
|
||||
[layer.id, "tagRenderings", found["id"]],
|
||||
["AddContextToTranslations"]
|
||||
)
|
||||
["AddContextToTranslations"],
|
||||
),
|
||||
)
|
||||
matchingTrs[i] = found
|
||||
}
|
||||
|
@ -375,17 +376,17 @@ 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 +
|
||||
"`? ",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -420,9 +421,9 @@ 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),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -441,39 +442,39 @@ class ExpandTagRendering extends Conversion<
|
|||
const candidates = Utils.sortedByLevenshteinDistance(
|
||||
layerName,
|
||||
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
|
||||
}
|
||||
|
@ -498,13 +499,13 @@ class DetectInline extends DesugaringStep<QuestionableTagRenderingConfigJson> {
|
|||
super(
|
||||
"If no 'inline' is set on the freeform key, it will be automatically added. If no special renderings are used, it'll be set to true",
|
||||
["freeform.inline"],
|
||||
"DetectInline"
|
||||
"DetectInline",
|
||||
)
|
||||
}
|
||||
|
||||
convert(
|
||||
json: QuestionableTagRenderingConfigJson,
|
||||
context: ConversionContext
|
||||
context: ConversionContext,
|
||||
): QuestionableTagRenderingConfigJson {
|
||||
if (json.freeform === undefined) {
|
||||
return json
|
||||
|
@ -527,7 +528,7 @@ class DetectInline extends DesugaringStep<QuestionableTagRenderingConfigJson> {
|
|||
if (json.freeform.inline === true) {
|
||||
context.err(
|
||||
"'inline' is set, but the rendering contains a special visualisation...\n " +
|
||||
spec[key]
|
||||
spec[key],
|
||||
)
|
||||
}
|
||||
json = JSON.parse(JSON.stringify(json))
|
||||
|
@ -550,7 +551,7 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
|||
super(
|
||||
"Adds a 'questions'-object if no question element is added yet",
|
||||
["tagRenderings"],
|
||||
"AddQuestionBox"
|
||||
"AddQuestionBox",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -574,18 +575,18 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
|||
json.tagRenderings = [...json.tagRenderings]
|
||||
const allSpecials: Exclude<RenderingSpecification, string>[] = <any>(
|
||||
ValidationUtils.getAllSpecialVisualisations(
|
||||
<QuestionableTagRenderingConfigJson[]>json.tagRenderings
|
||||
<QuestionableTagRenderingConfigJson[]>json.tagRenderings,
|
||||
).filter((spec) => typeof spec !== "string")
|
||||
)
|
||||
|
||||
const questionSpecials = allSpecials.filter((sp) => sp.func.funcName === "questions")
|
||||
const noLabels = questionSpecials.filter(
|
||||
(sp) => sp.args.length === 0 || sp.args[0].trim() === ""
|
||||
(sp) => sp.args.length === 0 || sp.args[0].trim() === "",
|
||||
)
|
||||
|
||||
if (noLabels.length > 1) {
|
||||
context.err(
|
||||
"Multiple 'questions'-visualisations found which would show _all_ questions. Don't do this"
|
||||
"Multiple 'questions'-visualisations found which would show _all_ questions. Don't do this",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -593,9 +594,9 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
|||
const allLabels = new Set(
|
||||
[].concat(
|
||||
...json.tagRenderings.map(
|
||||
(tr) => (<QuestionableTagRenderingConfigJson>tr).labels ?? []
|
||||
)
|
||||
)
|
||||
(tr) => (<QuestionableTagRenderingConfigJson>tr).labels ?? [],
|
||||
),
|
||||
),
|
||||
)
|
||||
const seen: Set<string> = new Set()
|
||||
for (const questionSpecial of questionSpecials) {
|
||||
|
@ -613,20 +614,20 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
|||
if (blacklisted?.length > 0 && used?.length > 0) {
|
||||
context.err(
|
||||
"The {questions()}-special rendering only supports either a blacklist OR a whitelist, but not both." +
|
||||
"\n Whitelisted: " +
|
||||
used.join(", ") +
|
||||
"\n Blacklisted: " +
|
||||
blacklisted.join(", ")
|
||||
"\n Whitelisted: " +
|
||||
used.join(", ") +
|
||||
"\n Blacklisted: " +
|
||||
blacklisted.join(", "),
|
||||
)
|
||||
}
|
||||
for (const usedLabel of used) {
|
||||
if (!allLabels.has(usedLabel)) {
|
||||
context.err(
|
||||
"This layers specifies a special question element for label `" +
|
||||
usedLabel +
|
||||
"`, but this label doesn't exist.\n" +
|
||||
" Available labels are " +
|
||||
Array.from(allLabels).join(", ")
|
||||
usedLabel +
|
||||
"`, but this label doesn't exist.\n" +
|
||||
" Available labels are " +
|
||||
Array.from(allLabels).join(", "),
|
||||
)
|
||||
}
|
||||
seen.add(usedLabel)
|
||||
|
@ -654,11 +655,12 @@ export class AddEditingElements extends DesugaringStep<LayerConfigJson> {
|
|||
private readonly _addedByDefaultAtTop: QuestionableTagRenderingConfigJson[]
|
||||
private readonly _addedByDefault: QuestionableTagRenderingConfigJson[]
|
||||
private readonly builtinQuestions: QuestionableTagRenderingConfigJson[]
|
||||
|
||||
constructor(desugaring: DesugaringContext) {
|
||||
super(
|
||||
"Add some editing elements, such as the delete button or the move button if they are configured. These used to be handled by the feature info box, but this has been replaced by special visualisation elements",
|
||||
[],
|
||||
"AddEditingElements"
|
||||
"AddEditingElements",
|
||||
)
|
||||
this._desugaring = desugaring
|
||||
this.builtinQuestions = Array.from(this._desugaring.tagRenderings?.values() ?? [])
|
||||
|
@ -688,13 +690,13 @@ export class AddEditingElements extends DesugaringStep<LayerConfigJson> {
|
|||
json.tagRenderings = [...(json.tagRenderings ?? [])]
|
||||
const allIds = new Set<string>(json.tagRenderings.map((tr) => tr["id"]))
|
||||
const specialVisualisations = ValidationUtils.getAllSpecialVisualisations(
|
||||
<any>json.tagRenderings
|
||||
<any>json.tagRenderings,
|
||||
)
|
||||
|
||||
const usedSpecialFunctions = new Set(
|
||||
specialVisualisations.map((sv) =>
|
||||
typeof sv === "string" ? undefined : sv.func.funcName
|
||||
)
|
||||
typeof sv === "string" ? undefined : sv.func.funcName,
|
||||
),
|
||||
)
|
||||
|
||||
/***** ADD TO TOP ****/
|
||||
|
@ -762,7 +764,7 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
|
|||
super(
|
||||
"Converts a 'special' translation into a regular translation which uses parameters",
|
||||
["special"],
|
||||
"RewriteSpecial"
|
||||
"RewriteSpecial",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -853,12 +855,12 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
|
|||
private static convertIfNeeded(
|
||||
input:
|
||||
| (object & {
|
||||
special: {
|
||||
type: string
|
||||
}
|
||||
})
|
||||
special: {
|
||||
type: string
|
||||
}
|
||||
})
|
||||
| any,
|
||||
context: ConversionContext
|
||||
context: ConversionContext,
|
||||
): any {
|
||||
const special = input["special"]
|
||||
if (special === undefined) {
|
||||
|
@ -868,7 +870,7 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
|
|||
const type = special["type"]
|
||||
if (type === undefined) {
|
||||
context.err(
|
||||
"A 'special'-block should define 'type' to indicate which visualisation should be used"
|
||||
"A 'special'-block should define 'type' to indicate which visualisation should be used",
|
||||
)
|
||||
return undefined
|
||||
}
|
||||
|
@ -878,10 +880,10 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
|
|||
const options = Utils.sortedByLevenshteinDistance(
|
||||
type,
|
||||
SpecialVisualizations.specialVisualizations,
|
||||
(sp) => sp.funcName
|
||||
(sp) => sp.funcName,
|
||||
)
|
||||
context.err(
|
||||
`Special visualisation '${type}' not found. Did you perhaps mean ${options[0].funcName}, ${options[1].funcName} or ${options[2].funcName}?\n\tFor all known special visualisations, please see https://github.com/pietervdvn/MapComplete/blob/develop/Docs/SpecialRenderings.md`
|
||||
`Special visualisation '${type}' not found. Did you perhaps mean ${options[0].funcName}, ${options[1].funcName} or ${options[2].funcName}?\n\tFor all known special visualisations, please see https://github.com/pietervdvn/MapComplete/blob/develop/Docs/SpecialRenderings.md`,
|
||||
)
|
||||
return undefined
|
||||
}
|
||||
|
@ -902,7 +904,7 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
|
|||
const byDistance = Utils.sortedByLevenshteinDistance(
|
||||
wrongArg,
|
||||
argNamesList,
|
||||
(x) => x
|
||||
(x) => x,
|
||||
)
|
||||
return `Unexpected argument in special block at ${context} with name '${wrongArg}'. Did you mean ${
|
||||
byDistance[0]
|
||||
|
@ -921,8 +923,8 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
|
|||
`Obligated parameter '${arg.name}' in special rendering of type ${
|
||||
vis.funcName
|
||||
} not found.\n The full special rendering specification is: '${JSON.stringify(
|
||||
input
|
||||
)}'\n ${arg.name}: ${arg.doc}`
|
||||
input,
|
||||
)}'\n ${arg.name}: ${arg.doc}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1024,7 +1026,7 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
|
|||
continue
|
||||
}
|
||||
Utils.WalkPath(path.path, json, (leaf, travelled) =>
|
||||
RewriteSpecial.convertIfNeeded(leaf, context.enter(travelled))
|
||||
RewriteSpecial.convertIfNeeded(leaf, context.enter(travelled)),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1058,7 +1060,7 @@ class ExpandIconBadges extends DesugaringStep<PointRenderingConfigJson> {
|
|||
} = badgesJson[i]
|
||||
const expanded = this._expand.convert(
|
||||
<QuestionableTagRenderingConfigJson>iconBadge.then,
|
||||
context.enters("iconBadges", i)
|
||||
context.enters("iconBadges", i),
|
||||
)
|
||||
if (expanded === undefined) {
|
||||
iconBadges.push(iconBadge)
|
||||
|
@ -1069,7 +1071,7 @@ class ExpandIconBadges extends DesugaringStep<PointRenderingConfigJson> {
|
|||
...expanded.map((resolved) => ({
|
||||
if: iconBadge.if,
|
||||
then: <MinimalTagRenderingConfigJson>resolved,
|
||||
}))
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1086,11 +1088,11 @@ class PreparePointRendering extends Fuse<PointRenderingConfigJson> {
|
|||
new Each(
|
||||
new On(
|
||||
"icon",
|
||||
new FirstOf(new ExpandTagRendering(state, layer, { applyCondition: false }))
|
||||
)
|
||||
)
|
||||
new FirstOf(new ExpandTagRendering(state, layer, { applyCondition: false })),
|
||||
),
|
||||
),
|
||||
),
|
||||
new ExpandIconBadges(state, layer)
|
||||
new ExpandIconBadges(state, layer),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1100,7 +1102,7 @@ class SetFullNodeDatabase extends DesugaringStep<LayerConfigJson> {
|
|||
super(
|
||||
"sets the fullNodeDatabase-bit if needed",
|
||||
["fullNodeDatabase"],
|
||||
"SetFullNodeDatabase"
|
||||
"SetFullNodeDatabase",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1129,7 +1131,7 @@ class ExpandMarkerRenderings extends DesugaringStep<IconConfigJson> {
|
|||
super(
|
||||
"Expands tagRenderings in the icons, if needed",
|
||||
["icon", "color"],
|
||||
"ExpandMarkerRenderings"
|
||||
"ExpandMarkerRenderings",
|
||||
)
|
||||
this._layer = layer
|
||||
this._state = state
|
||||
|
@ -1161,7 +1163,7 @@ class AddFavouriteBadges extends DesugaringStep<LayerConfigJson> {
|
|||
super(
|
||||
"Adds the favourite heart to the title and the rendering badges",
|
||||
[],
|
||||
"AddFavouriteBadges"
|
||||
"AddFavouriteBadges",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1186,7 +1188,7 @@ export class AddRatingBadge extends DesugaringStep<LayerConfigJson> {
|
|||
super(
|
||||
"Adds the 'rating'-element if a reviews-element is used in the tagRenderings",
|
||||
["titleIcons"],
|
||||
"AddRatingBadge"
|
||||
"AddRatingBadge",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1205,8 +1207,8 @@ export class AddRatingBadge extends DesugaringStep<LayerConfigJson> {
|
|||
|
||||
const specialVis: Exclude<RenderingSpecification, string>[] = <
|
||||
Exclude<RenderingSpecification, string>[]
|
||||
>ValidationUtils.getAllSpecialVisualisations(<any>json.tagRenderings).filter(
|
||||
(rs) => typeof rs !== "string"
|
||||
>ValidationUtils.getAllSpecialVisualisations(<any>json.tagRenderings).filter(
|
||||
(rs) => typeof rs !== "string",
|
||||
)
|
||||
const funcs = new Set<string>(specialVis.map((rs) => rs.func.funcName))
|
||||
|
||||
|
@ -1222,12 +1224,12 @@ export class AutoTitleIcon extends DesugaringStep<LayerConfigJson> {
|
|||
super(
|
||||
"The auto-icon creates a (non-clickable) title icon based on a tagRendering which has icons",
|
||||
["titleIcons"],
|
||||
"AutoTitleIcon"
|
||||
"AutoTitleIcon",
|
||||
)
|
||||
}
|
||||
|
||||
private createTitleIconsBasedOn(
|
||||
tr: QuestionableTagRenderingConfigJson
|
||||
tr: QuestionableTagRenderingConfigJson,
|
||||
): TagRenderingConfigJson | undefined {
|
||||
const mappings: { if: TagConfigJson; then: string }[] = tr.mappings
|
||||
?.filter((m) => m.icon !== undefined)
|
||||
|
@ -1257,7 +1259,7 @@ export class AutoTitleIcon extends DesugaringStep<LayerConfigJson> {
|
|||
return undefined
|
||||
}
|
||||
return this.createTitleIconsBasedOn(<any>tr)
|
||||
})
|
||||
}),
|
||||
)
|
||||
json.titleIcons.splice(allAutoIndex, 1, ...generated)
|
||||
return json
|
||||
|
@ -1286,8 +1288,8 @@ export class AutoTitleIcon extends DesugaringStep<LayerConfigJson> {
|
|||
.enters("titleIcons", i)
|
||||
.warn(
|
||||
"TagRendering with id " +
|
||||
trId +
|
||||
" does not have any icons, not generating an icon for this"
|
||||
trId +
|
||||
" does not have any icons, not generating an icon for this",
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
@ -1297,13 +1299,48 @@ export class AutoTitleIcon extends DesugaringStep<LayerConfigJson> {
|
|||
}
|
||||
}
|
||||
|
||||
class DeriveSource extends DesugaringStep<LayerConfigJson> {
|
||||
|
||||
constructor() {
|
||||
super("If no source is given, automatically derives the osmTags by 'or'-ing all the preset tags", ["source"], "DeriveSource")
|
||||
}
|
||||
|
||||
public convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson {
|
||||
if (json.source) {
|
||||
return json
|
||||
}
|
||||
if (!json.presets) {
|
||||
context.err("No source tags given. Trying to derive the source-tags based on the presets, but no presets are given")
|
||||
return json
|
||||
}
|
||||
|
||||
json = { ...json }
|
||||
|
||||
const raw = { or: json.presets.map(pr => ({ and: pr.tags })) }
|
||||
const osmTags = TagUtils.optimzeJson(raw)
|
||||
if (osmTags === false) {
|
||||
context.err("The preset-tags optimize to 'false' " + JSON.stringify(raw))
|
||||
return json
|
||||
}
|
||||
if (osmTags === true) {
|
||||
context.err("The preset-tags optimize to 'true' " + JSON.stringify(raw))
|
||||
return json
|
||||
}
|
||||
|
||||
json.source = { osmTags }
|
||||
return json
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class PrepareLayer extends Fuse<LayerConfigJson> {
|
||||
constructor(
|
||||
state: DesugaringContext,
|
||||
options?: { addTagRenderingsToContext?: false | boolean }
|
||||
options?: { addTagRenderingsToContext?: false | boolean },
|
||||
) {
|
||||
super(
|
||||
"Fully prepares and expands a layer for the LayerConfig.",
|
||||
new DeriveSource(),
|
||||
new On("tagRenderings", new Each(new RewriteSpecial())),
|
||||
new On("tagRenderings", new Concat(new ExpandRewrite()).andThenF(Utils.Flatten)),
|
||||
new On(
|
||||
|
@ -1312,8 +1349,8 @@ export class PrepareLayer extends Fuse<LayerConfigJson> {
|
|||
new Concat(
|
||||
new ExpandTagRendering(state, layer, {
|
||||
addToContext: options?.addTagRenderingsToContext ?? false,
|
||||
})
|
||||
)
|
||||
}),
|
||||
),
|
||||
),
|
||||
new On("tagRenderings", new Each(new DetectInline())),
|
||||
new AddQuestionBox(),
|
||||
|
@ -1326,11 +1363,11 @@ export class PrepareLayer extends Fuse<LayerConfigJson> {
|
|||
new On<PointRenderingConfigJson[], LayerConfigJson>(
|
||||
"pointRendering",
|
||||
(layer) =>
|
||||
new Each(new On("marker", new Each(new ExpandMarkerRenderings(state, layer))))
|
||||
new Each(new On("marker", new Each(new ExpandMarkerRenderings(state, layer)))),
|
||||
),
|
||||
new On<PointRenderingConfigJson[], LayerConfigJson>(
|
||||
"pointRendering",
|
||||
(layer) => new Each(new PreparePointRendering(state, layer))
|
||||
(layer) => new Each(new PreparePointRendering(state, layer)),
|
||||
),
|
||||
new SetDefault("titleIcons", ["icons.defaults"]),
|
||||
new AddRatingBadge(),
|
||||
|
@ -1339,9 +1376,9 @@ export class PrepareLayer extends Fuse<LayerConfigJson> {
|
|||
new On(
|
||||
"titleIcons",
|
||||
(layer) =>
|
||||
new Concat(new ExpandTagRendering(state, layer, { noHardcodedStrings: true }))
|
||||
new Concat(new ExpandTagRendering(state, layer, { noHardcodedStrings: true })),
|
||||
),
|
||||
new ExpandFilter(state)
|
||||
new ExpandFilter(state),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import DeleteConfig from "../DeleteConfig"
|
|||
import { And } from "../../../Logic/Tags/And"
|
||||
import { DoesImageExist, ValidateFilter, ValidatePointRendering } from "./Validation"
|
||||
import { ValidateTagRenderings } from "./ValidateTagRenderings"
|
||||
import { TagsFilterClosed } from "../../../Logic/Tags/TagTypes"
|
||||
|
||||
export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
||||
private readonly _isBuiltin: boolean
|
||||
|
@ -24,7 +25,7 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
path: string,
|
||||
isBuiltin: boolean,
|
||||
doesImageExist: DoesImageExist,
|
||||
studioValidations: boolean
|
||||
studioValidations: boolean,
|
||||
) {
|
||||
super("Runs various checks against common mistakes for a layer", [], "PrevalidateLayer")
|
||||
this._path = path
|
||||
|
@ -47,18 +48,21 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
}
|
||||
|
||||
if (json.source === undefined) {
|
||||
context
|
||||
.enter("source")
|
||||
.err(
|
||||
"No source section is defined; please define one as data is not loaded otherwise"
|
||||
)
|
||||
if (json.presets?.length < 1) {
|
||||
|
||||
context
|
||||
.enter("source")
|
||||
.err(
|
||||
"No source section is defined; please define one as data is not loaded otherwise",
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (json.source === "special" || json.source === "special:library") {
|
||||
} else if (json.source && json.source["osmTags"] === undefined) {
|
||||
context
|
||||
.enters("source", "osmTags")
|
||||
.err(
|
||||
"No osmTags defined in the source section - these should always be present, even for geojson layer"
|
||||
"No osmTags defined in the source section - these should always be present, even for geojson layer",
|
||||
)
|
||||
} else {
|
||||
const osmTags = TagUtils.Tag(json.source["osmTags"], context + "source.osmTags")
|
||||
|
@ -67,7 +71,7 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
.enters("source", "osmTags")
|
||||
.err(
|
||||
"The source states tags which give a very wide selection: it only uses negative expressions, which will result in too much and unexpected data. Add at least one required tag. The tags are:\n\t" +
|
||||
osmTags.asHumanString(false, false, {})
|
||||
osmTags.asHumanString(false, false, {}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -93,10 +97,10 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
.enter("syncSelection")
|
||||
.err(
|
||||
"Invalid sync-selection: must be one of " +
|
||||
LayerConfig.syncSelectionAllowed.map((v) => `'${v}'`).join(", ") +
|
||||
" but got '" +
|
||||
json.syncSelection +
|
||||
"'"
|
||||
LayerConfig.syncSelectionAllowed.map((v) => `'${v}'`).join(", ") +
|
||||
" but got '" +
|
||||
json.syncSelection +
|
||||
"'",
|
||||
)
|
||||
}
|
||||
if (json["pointRenderings"]?.length > 0) {
|
||||
|
@ -115,7 +119,7 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
}
|
||||
|
||||
json.pointRendering?.forEach((pr, i) =>
|
||||
this._validatePointRendering.convert(pr, context.enters("pointeRendering", i))
|
||||
this._validatePointRendering.convert(pr, context.enters("pointeRendering", i)),
|
||||
)
|
||||
|
||||
if (json["mapRendering"]) {
|
||||
|
@ -132,8 +136,8 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
if (!Constants.priviliged_layers.find((x) => x == json.id)) {
|
||||
context.err(
|
||||
"Layer " +
|
||||
json.id +
|
||||
" uses 'special' as source.osmTags. However, this layer is not a priviliged layer"
|
||||
json.id +
|
||||
" uses 'special' as source.osmTags. However, this layer is not a privileged layer",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -148,19 +152,19 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
context
|
||||
.enter("title")
|
||||
.err(
|
||||
"This layer does not have a title defined but it does have tagRenderings. Not having a title will disable the popups, resulting in an unclickable element. Please add a title. If not having a popup is intended and the tagrenderings need to be kept (e.g. in a library layer), set `title: null` to disable this error."
|
||||
"This layer does not have a title defined but it does have tagRenderings. Not having a title will disable the popups, resulting in an unclickable element. Please add a title. If not having a popup is intended and the tagrenderings need to be kept (e.g. in a library layer), set `title: null` to disable this error.",
|
||||
)
|
||||
}
|
||||
if (json.title === null) {
|
||||
context.info(
|
||||
"Title is `null`. This results in an element that cannot be clicked - even though tagRenderings is set."
|
||||
"Title is `null`. This results in an element that cannot be clicked - even though tagRenderings is set.",
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
// Check for multiple, identical builtin questions - usability for studio users
|
||||
const duplicates = Utils.Duplicates(
|
||||
<string[]>json.tagRenderings.filter((tr) => typeof tr === "string")
|
||||
<string[]>json.tagRenderings.filter((tr) => typeof tr === "string"),
|
||||
)
|
||||
for (let i = 0; i < json.tagRenderings.length; i++) {
|
||||
const tagRendering = json.tagRenderings[i]
|
||||
|
@ -190,7 +194,7 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
{
|
||||
// duplicate ids in tagrenderings check
|
||||
const duplicates = Utils.NoNull(
|
||||
Utils.Duplicates(Utils.NoNull((json.tagRenderings ?? []).map((tr) => tr["id"])))
|
||||
Utils.Duplicates(Utils.NoNull((json.tagRenderings ?? []).map((tr) => tr["id"]))),
|
||||
)
|
||||
if (duplicates.length > 0) {
|
||||
// It is tempting to add an index to this warning; however, due to labels the indices here might be different from the index in the tagRendering list
|
||||
|
@ -198,11 +202,11 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
.enter("tagRenderings")
|
||||
.err(
|
||||
"Some tagrenderings have a duplicate id: " +
|
||||
duplicates.join(", ") +
|
||||
"\n" +
|
||||
JSON.stringify(
|
||||
json.tagRenderings.filter((tr) => duplicates.indexOf(tr["id"]) >= 0)
|
||||
)
|
||||
duplicates.join(", ") +
|
||||
"\n" +
|
||||
JSON.stringify(
|
||||
json.tagRenderings.filter((tr) => duplicates.indexOf(tr["id"]) >= 0),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -235,8 +239,8 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
if (json["overpassTags"] !== undefined) {
|
||||
context.err(
|
||||
"Layer " +
|
||||
json.id +
|
||||
'still uses the old \'overpassTags\'-format. Please use "source": {"osmTags": <tags>}\' instead of "overpassTags": <tags> (note: this isn\'t your fault, the custom theme generator still spits out the old format)'
|
||||
json.id +
|
||||
"still uses the old 'overpassTags'-format. Please use \"source\": {\"osmTags\": <tags>}' instead of \"overpassTags\": <tags> (note: this isn't your fault, the custom theme generator still spits out the old format)",
|
||||
)
|
||||
}
|
||||
const forbiddenTopLevel = [
|
||||
|
@ -256,7 +260,7 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
}
|
||||
if (json["hideUnderlayingFeaturesMinPercentage"] !== undefined) {
|
||||
context.err(
|
||||
"Layer " + json.id + " contains an old 'hideUnderlayingFeaturesMinPercentage'"
|
||||
"Layer " + json.id + " contains an old 'hideUnderlayingFeaturesMinPercentage'",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -273,9 +277,9 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
if (this._path != undefined && this._path.indexOf(expected) < 0) {
|
||||
context.err(
|
||||
"Layer is in an incorrect place. The path is " +
|
||||
this._path +
|
||||
", but expected " +
|
||||
expected
|
||||
this._path +
|
||||
", but expected " +
|
||||
expected,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -293,13 +297,13 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
.enter(["tagRenderings", ...emptyIndexes])
|
||||
.err(
|
||||
`Some tagrendering-ids are empty or have an emtpy string; this is not allowed (at ${emptyIndexes.join(
|
||||
","
|
||||
)}])`
|
||||
",",
|
||||
)}])`,
|
||||
)
|
||||
}
|
||||
|
||||
const duplicateIds = Utils.Duplicates(
|
||||
(json.tagRenderings ?? [])?.map((f) => f["id"]).filter((id) => id !== "questions")
|
||||
(json.tagRenderings ?? [])?.map((f) => f["id"]).filter((id) => id !== "questions"),
|
||||
)
|
||||
if (duplicateIds.length > 0 && !Utils.runningFromConsole) {
|
||||
context
|
||||
|
@ -323,7 +327,7 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
if (json.tagRenderings !== undefined) {
|
||||
new On(
|
||||
"tagRenderings",
|
||||
new Each(new ValidateTagRenderings(json, this._doesImageExist))
|
||||
new Each(new ValidateTagRenderings(json, this._doesImageExist)),
|
||||
).convert(json, context)
|
||||
}
|
||||
|
||||
|
@ -350,7 +354,7 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
context
|
||||
.enters("pointRendering", i, "marker", indexM, "icon", "condition")
|
||||
.err(
|
||||
"Don't set a condition in a marker as this will result in an invisible but clickable element. Use extra filters in the source instead."
|
||||
"Don't set a condition in a marker as this will result in an invisible but clickable element. Use extra filters in the source instead.",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -361,8 +365,11 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
if (typeof json.source === "string") {
|
||||
context.enter("presets").err("A special layer cannot have presets")
|
||||
}
|
||||
// Check that a preset will be picked up by the layer itself
|
||||
const baseTags = TagUtils.Tag(json.source["osmTags"])
|
||||
let baseTags: TagsFilterClosed
|
||||
if (json.source) {
|
||||
// Check that a preset will be picked up by the layer itself
|
||||
baseTags = TagUtils.Tag(json.source["osmTags"])
|
||||
}
|
||||
for (let i = 0; i < json.presets.length; i++) {
|
||||
const preset = json.presets[i]
|
||||
if (!preset) {
|
||||
|
@ -382,16 +389,18 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
for (const tag of tags.asChange({ id: "node/-1" })) {
|
||||
properties[tag.k] = tag.v
|
||||
}
|
||||
const doMatch = baseTags.matchesProperties(properties)
|
||||
if (!doMatch) {
|
||||
context
|
||||
.enters("presets", i, "tags")
|
||||
.err(
|
||||
"This preset does not match the required tags of this layer. This implies that a newly added point will not show up.\n A newly created point will have properties: " +
|
||||
if(baseTags) {
|
||||
const doMatch = baseTags.matchesProperties(properties)
|
||||
if (!doMatch) {
|
||||
context
|
||||
.enters("presets", i, "tags")
|
||||
.err(
|
||||
"This preset does not match the required tags of this layer. This implies that a newly added point will not show up.\n A newly created point will have properties: " +
|
||||
tags.asHumanString(false, false, {}) +
|
||||
"\n The required tags are: " +
|
||||
baseTags.asHumanString(false, false, {})
|
||||
)
|
||||
baseTags.asHumanString(false, false, {}),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,9 +63,11 @@ export interface LayerConfigJson {
|
|||
*
|
||||
* types: Load data with specific tags from OpenStreetMap ; Load data from an external geojson source ;
|
||||
* typesdefault: 0
|
||||
* ifunset: Determine the tags automatically based on the presets
|
||||
* group: Basic
|
||||
*/
|
||||
source:
|
||||
| undefined
|
||||
| "special"
|
||||
| "special:library"
|
||||
| {
|
||||
|
|
|
@ -81,7 +81,11 @@ export default class LayerConfig extends WithContextLoader {
|
|||
}
|
||||
|
||||
this.syncSelection = json.syncSelection ?? "no"
|
||||
if (typeof json.source !== "string") {
|
||||
if(!json.source){
|
||||
this.source = new SourceConfig({
|
||||
osmTags: TagUtils.Tag({or: json.presets.map(pr => ({and:pr.tags}))})
|
||||
})
|
||||
}else if (typeof json.source !== "string") {
|
||||
this.maxAgeOfCache = json.source["maxCacheAge"] ?? 24 * 60 * 60 * 30
|
||||
this.source = new SourceConfig(
|
||||
{
|
||||
|
@ -93,7 +97,7 @@ export default class LayerConfig extends WithContextLoader {
|
|||
mercatorCrs: json.source["mercatorCrs"],
|
||||
idKey: json.source["idKey"],
|
||||
},
|
||||
json.id
|
||||
json.id,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -112,7 +116,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 = []
|
||||
|
@ -182,7 +186,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,
|
||||
|
@ -196,7 +200,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 = []
|
||||
|
@ -204,7 +208,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 = []
|
||||
|
@ -216,7 +220,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 (
|
||||
|
@ -238,7 +242,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 (
|
||||
|
@ -257,7 +261,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)
|
||||
|
@ -268,8 +272,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 (
|
||||
|
@ -279,7 +283,7 @@ 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}]`),
|
||||
)
|
||||
|
||||
if (
|
||||
|
@ -355,7 +359,7 @@ export default class LayerConfig extends WithContextLoader {
|
|||
|
||||
public GetBaseTags(): Record<string, string> {
|
||||
return 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" }],
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -368,7 +372,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")
|
||||
|
@ -376,32 +380,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`",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -411,12 +415,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.",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -426,7 +430,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) {
|
||||
|
@ -442,15 +446,15 @@ export default class LayerConfig extends WithContextLoader {
|
|||
" into the layout as it depends on it: ",
|
||||
dep.reason,
|
||||
"(" + dep.context + ")",
|
||||
].join(" ")
|
||||
].join(" "),
|
||||
)
|
||||
}
|
||||
|
||||
for (const revDep of Utils.Dedup(layerIsNeededBy?.get(this.id) ?? [])) {
|
||||
extraProps.push(
|
||||
["This layer is needed as dependency for layer", `[${revDep}](#${revDep})`].join(
|
||||
" "
|
||||
)
|
||||
" ",
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -461,10 +465,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 [
|
||||
|
@ -479,7 +483,7 @@ export default class LayerConfig extends WithContextLoader {
|
|||
: `[${values.type}](../SpecialInputElements.md#${values.type})`,
|
||||
embedded.join(" "),
|
||||
]
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
let quickOverview: string[] = []
|
||||
|
@ -489,7 +493,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,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
@ -523,19 +527,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, {}) +
|
||||
"**",
|
||||
)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue