forked from MapComplete/MapComplete
Themes: move generated themes into assets, remove known_themes, support pruning of borrowed icons
This commit is contained in:
parent
310b973846
commit
ee64d84d27
18 changed files with 431 additions and 400 deletions
|
@ -41,7 +41,6 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
|
||||
"minzoom": 15,
|
||||
"title": {
|
||||
"render": {
|
||||
|
|
|
@ -2327,6 +2327,28 @@
|
|||
"render": "Camper site {name}"
|
||||
}
|
||||
},
|
||||
"charge_point": {
|
||||
"description": "Layer showing individual charge points within a charging station",
|
||||
"name": "Charge points",
|
||||
"presets": {
|
||||
"0": {
|
||||
"description": "Add an individual charge point within a larger charging station",
|
||||
"title": "a charge point"
|
||||
}
|
||||
},
|
||||
"tagRenderings": {
|
||||
"ref": {
|
||||
"freeform": {
|
||||
"placeholder": "Reference number of the charge point, e.g. 2126"
|
||||
},
|
||||
"question": "What is the reference number of this charge point?",
|
||||
"render": "The reference of this charge point is {ref}"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"render": "Charge point"
|
||||
}
|
||||
},
|
||||
"charging_station": {
|
||||
"description": "A charging station",
|
||||
"filter": {
|
||||
|
|
|
@ -205,7 +205,6 @@
|
|||
"jspdf": "^2.5.1",
|
||||
"latlon2country": "^1.2.6",
|
||||
"libphonenumber-js": "^1.10.8",
|
||||
"lz-string": "^1.4.4",
|
||||
"mangrove-reviews-typescript": "^1.1.0",
|
||||
"maplibre-gl": "^4.1.1",
|
||||
"marked": "^12.0.2",
|
||||
|
|
|
@ -180,6 +180,7 @@ class DownloadNsiLogos extends Script {
|
|||
],
|
||||
filter: [
|
||||
<any>{
|
||||
"#":"ignore-possible-duplicate",
|
||||
id: type,
|
||||
strict: true,
|
||||
options: [{ question: type }, ...filterOptions],
|
||||
|
|
|
@ -9,7 +9,7 @@ import ScriptUtils from "./ScriptUtils"
|
|||
import Translations from "../src/UI/i18n/Translations"
|
||||
import themeOverview from "../src/assets/generated/theme_overview.json"
|
||||
import ThemeConfig from "../src/Models/ThemeConfig/ThemeConfig"
|
||||
import bookcases from "../src/assets/generated/themes/bookcases.json"
|
||||
import bookcases from "../public/assets/generated/themes/bookcases.json"
|
||||
import fakedom from "fake-dom"
|
||||
import unit from "../src/assets/generated/layers/unit.json"
|
||||
import Hotkeys from "../src/UI/Base/Hotkeys"
|
||||
|
|
|
@ -140,7 +140,7 @@ class AddIconSummary extends DesugaringStep<{ raw: LayerConfigJson; parsed: Laye
|
|||
|
||||
class LayerOverviewUtils extends Script {
|
||||
public static readonly layerPath = "./src/assets/generated/layers/"
|
||||
public static readonly themePath = "./src/assets/generated/themes/"
|
||||
public static readonly themePath = "./public/assets/generated/themes/"
|
||||
|
||||
constructor() {
|
||||
super("Reviews and generates the compiled themes")
|
||||
|
@ -319,12 +319,12 @@ class LayerOverviewUtils extends Script {
|
|||
keywords,
|
||||
layers: theme.layers.filter((l) => sharedLayers.has(l["id"])).map((l) => l["id"]),
|
||||
}
|
||||
perId.set(theme.id, data)
|
||||
perId.set(data.id, data)
|
||||
}
|
||||
|
||||
const sorted = Constants.themeOrder.map((id) => {
|
||||
if (!perId.has(id)) {
|
||||
throw "Ordered theme id " + id + " not found"
|
||||
throw "Ordered theme '" + id + "' not found"
|
||||
}
|
||||
return perId.get(id)
|
||||
})
|
||||
|
|
|
@ -298,8 +298,8 @@ class GenerateLayouts extends Script {
|
|||
Origin: "https://mapcomplete.org",
|
||||
})
|
||||
urls.push(...(f.properties["connect-src"] ?? []))
|
||||
for (const key of Object.keys(styleSpec?.sources ?? {})) {
|
||||
const url = styleSpec.sources[key].url
|
||||
for (const key of Object.keys(styleSpec?.["sources"] ?? {})) {
|
||||
const url = styleSpec["sources"][key].url
|
||||
if (!url) {
|
||||
continue
|
||||
}
|
||||
|
@ -585,7 +585,7 @@ class GenerateLayouts extends Script {
|
|||
const filename = "index_" + theme.id + ".ts"
|
||||
|
||||
const imports = [
|
||||
`import layout from "./src/assets/generated/themes/${theme.id}.json"`,
|
||||
`import layout from "./public/assets/generated/themes/${theme.id}.json"`,
|
||||
`import { ThemeMetaTagging } from "./src/assets/generated/metatagging/${theme.id}"`,
|
||||
]
|
||||
for (const layerName of Constants.added_by_default) {
|
||||
|
@ -640,7 +640,7 @@ class GenerateLayouts extends Script {
|
|||
if (theme !== undefined) {
|
||||
console.warn("Only generating layout " + theme)
|
||||
}
|
||||
const paths = ScriptUtils.readDirRecSync("./src/assets/generated/themes/",1)
|
||||
const paths = ScriptUtils.readDirRecSync("./public/assets/generated/themes/",1)
|
||||
for (const i in paths) {
|
||||
const layoutConfigJson = <ThemeConfigJson> JSON.parse(readFileSync(paths[i], "utf8"))
|
||||
if (theme !== undefined && layoutConfigJson.id !== theme) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
mkdir -p ./src/assets/generated/layers
|
||||
echo '{"layers": []}' > ./src/assets/generated/known_layers.json
|
||||
rm -f ./src/assets/generated/layers/*.json
|
||||
rm -f ./src/assets/generated/themes/*.json
|
||||
rm -f ./public/assets/generated/themes/*.json
|
||||
cp ./assets/layers/usersettings/usersettings.json ./src/assets/generated/layers/usersettings.json
|
||||
echo '{}' > ./src/assets/generated/layers/favourite.json
|
||||
echo '{}' > ./src/assets/generated/layers/summary.json
|
||||
|
|
|
@ -5,6 +5,7 @@ import { AllSharedLayers } from "./AllSharedLayers"
|
|||
import Constants from "../Models/Constants"
|
||||
import ScriptUtils from "../../scripts/ScriptUtils"
|
||||
import { readFileSync } from "fs"
|
||||
import { LayerConfigJson } from "../Models/ThemeConfig/Json/LayerConfigJson"
|
||||
|
||||
/**
|
||||
* Somewhat of a dictionary, which lazily parses needed themes
|
||||
|
@ -14,14 +15,14 @@ export class AllKnownLayoutsLazy {
|
|||
private readonly dict: Map<string, ThemeConfig> = new Map()
|
||||
|
||||
constructor(includeFavouriteLayer = true) {
|
||||
const paths = ScriptUtils.readDirRecSync("./src/assets/generated/themes/",1)
|
||||
const paths = ScriptUtils.readDirRecSync("./public/assets/generated/themes/",1)
|
||||
|
||||
for (const path of paths) {
|
||||
const themeConfigJson = <ThemeConfigJson> JSON.parse(readFileSync(path, "utf8"))
|
||||
for (const layerId of Constants.added_by_default) {
|
||||
if (layerId === "favourite" && favourite.id) {
|
||||
if (includeFavouriteLayer) {
|
||||
themeConfigJson.layers.push(favourite)
|
||||
themeConfigJson.layers.push(<LayerConfigJson> favourite)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -7,12 +7,9 @@ export class AllSharedLayers {
|
|||
public static sharedLayers: Map<string, LayerConfig> = AllSharedLayers.getSharedLayers()
|
||||
public static getSharedLayersConfigs(): Map<string, LayerConfigJson> {
|
||||
const sharedLayers = new Map<string, LayerConfigJson>()
|
||||
for (const layer of (known_layers).layers) {
|
||||
for (const layer of known_layers["layers"]) {
|
||||
if(layer.id === undefined){
|
||||
console.error("Layer without id! "+JSON.stringify(layer).slice(0,80), known_layers.layers.length)
|
||||
continue
|
||||
}else{
|
||||
console.log("Loaded",layer.id)
|
||||
}
|
||||
sharedLayers.set(layer.id, <any> layer)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import ThemeConfig from "../Models/ThemeConfig/ThemeConfig"
|
||||
import ThemeConfig, { MinimalThemeInformation } from "../Models/ThemeConfig/ThemeConfig"
|
||||
import { QueryParameters } from "./Web/QueryParameters"
|
||||
import { AllKnownLayouts } from "../Customizations/AllKnownLayouts"
|
||||
import { FixedUiElement } from "../UI/Base/FixedUiElement"
|
||||
import { Utils } from "../Utils"
|
||||
import LZString from "lz-string"
|
||||
import { FixLegacyTheme } from "../Models/ThemeConfig/Conversion/LegacyJsonConvert"
|
||||
import { LayerConfigJson } from "../Models/ThemeConfig/Json/LayerConfigJson"
|
||||
import known_layers from "../assets/generated/known_layers.json"
|
||||
|
@ -15,10 +13,10 @@ import questions from "../assets/generated/layers/questions.json"
|
|||
import { DoesImageExist, PrevalidateTheme } from "../Models/ThemeConfig/Conversion/Validation"
|
||||
import { DesugaringContext } from "../Models/ThemeConfig/Conversion/Conversion"
|
||||
import { TagRenderingConfigJson } from "../Models/ThemeConfig/Json/TagRenderingConfigJson"
|
||||
import Hash from "./Web/Hash"
|
||||
import { QuestionableTagRenderingConfigJson } from "../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
|
||||
import { ThemeConfigJson } from "../Models/ThemeConfig/Json/ThemeConfigJson"
|
||||
import { ValidateThemeAndLayers } from "../Models/ThemeConfig/Conversion/ValidateThemeAndLayers"
|
||||
import * as theme_overview from "../assets/generated/theme_overview.json"
|
||||
|
||||
export default class DetermineTheme {
|
||||
private static readonly _knownImages = new Set(Array.from(licenses).map((l) => l.path))
|
||||
|
@ -87,14 +85,15 @@ export default class DetermineTheme {
|
|||
"The layout to load into MapComplete"
|
||||
).data
|
||||
const id = layoutId?.toLowerCase()
|
||||
const layouts = AllKnownLayouts.allKnownLayouts
|
||||
if (layouts.size() == 0) {
|
||||
const themes: MinimalThemeInformation[] = theme_overview.themes
|
||||
if (themes.length == 0) {
|
||||
throw "Build failed or running, no layouts are known at all"
|
||||
}
|
||||
if (layouts.getConfig(id) === undefined) {
|
||||
const themeInfo = themes.find(th => th.id === id)
|
||||
if (themeInfo === undefined) {
|
||||
const alternatives = Utils.sortedByLevenshteinDistance(
|
||||
id,
|
||||
Array.from(layouts.keys()),
|
||||
themes.map(th => th.id),
|
||||
(i) => i
|
||||
).slice(0, 3)
|
||||
const msg = `No builtin map theme with name ${layoutId} exists. Perhaps you meant one of ${alternatives.join(
|
||||
|
@ -102,7 +101,10 @@ export default class DetermineTheme {
|
|||
)}`
|
||||
throw msg
|
||||
}
|
||||
return layouts.get(id)
|
||||
// Actually fetch the theme
|
||||
|
||||
const config = await Utils.downloadJsonCached<ThemeConfigJson>("./assets/generated/themes/"+id+".json", 1000*60*60*60)
|
||||
return new ThemeConfig(config, true)
|
||||
}
|
||||
|
||||
private static getSharedTagRenderings(): Map<string, QuestionableTagRenderingConfigJson> {
|
||||
|
|
370
src/Models/ThemeConfig/Conversion/ExpandTagRendering.ts
Normal file
370
src/Models/ThemeConfig/Conversion/ExpandTagRendering.ts
Normal file
|
@ -0,0 +1,370 @@
|
|||
import { Conversion, DesugaringContext } from "./Conversion"
|
||||
import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson"
|
||||
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
||||
import { ConversionContext } from "./ConversionContext"
|
||||
import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson"
|
||||
import { TagUtils } from "../../../Logic/Tags/TagUtils"
|
||||
import { Utils } from "../../../Utils"
|
||||
import { AddContextToTranslations } from "./AddContextToTranslations"
|
||||
|
||||
export class ExpandTagRendering extends Conversion<
|
||||
| string
|
||||
| TagRenderingConfigJson
|
||||
| {
|
||||
builtin: string | string[]
|
||||
override: any
|
||||
},
|
||||
TagRenderingConfigJson[]
|
||||
> {
|
||||
private readonly _state: DesugaringContext
|
||||
private readonly _tagRenderingsByLabel: Map<string, (TagRenderingConfigJson & { id: string })[]>
|
||||
// Only used for self-reference
|
||||
private readonly _self: LayerConfigJson
|
||||
private readonly _options: {
|
||||
/* If true, will copy the 'osmSource'-tags into the condition */
|
||||
applyCondition?: true | boolean
|
||||
noHardcodedStrings?: false | boolean
|
||||
addToContext?: false | boolean
|
||||
}
|
||||
|
||||
constructor(
|
||||
state: DesugaringContext,
|
||||
self: LayerConfigJson,
|
||||
options?: {
|
||||
applyCondition?: true | boolean
|
||||
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",
|
||||
)
|
||||
this._state = state
|
||||
this._self = self
|
||||
this._options = options
|
||||
this._tagRenderingsByLabel = new Map<string, (TagRenderingConfigJson & { id: string })[]>()
|
||||
for (const trconfig of state.tagRenderings?.values() ?? []) {
|
||||
for (const label of trconfig["labels"] ?? []) {
|
||||
let withLabel = this._tagRenderingsByLabel.get(label)
|
||||
if (withLabel === undefined) {
|
||||
withLabel = []
|
||||
this._tagRenderingsByLabel.set(label, withLabel)
|
||||
}
|
||||
withLabel.push(trconfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public convert(
|
||||
spec: string | any,
|
||||
ctx: ConversionContext,
|
||||
): QuestionableTagRenderingConfigJson[] {
|
||||
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
|
||||
}
|
||||
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))
|
||||
result.push(...stable)
|
||||
if (this._options?.addToContext) {
|
||||
for (const tr of stable) {
|
||||
this._state.tagRenderings?.set(tr.id, tr)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result.push(tr)
|
||||
if (this._options?.addToContext) {
|
||||
this._state.tagRenderings?.set(tr["id"], <QuestionableTagRenderingConfigJson>tr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private pruneMappings<T extends (TagRenderingConfigJson & {
|
||||
id: string
|
||||
})>(tagRendering: T, ctx: ConversionContext): T {
|
||||
if (!tagRendering["strict"]) {
|
||||
return tagRendering
|
||||
}
|
||||
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"]}`)
|
||||
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 after = newMappings?.length ?? 0
|
||||
if (before - after > 0) {
|
||||
ctx.info(`Pruned mappings for ${tagRendering.id}, from ${before} to ${after} (removed ${before - after})`)
|
||||
}
|
||||
const tr = {
|
||||
...tagRendering,
|
||||
mappings: newMappings,
|
||||
}
|
||||
delete tr["strict"]
|
||||
return tr
|
||||
}
|
||||
|
||||
private lookup(name: string, ctx: ConversionContext): (TagRenderingConfigJson & { id: string })[] | undefined {
|
||||
const direct = this.directLookup(name)
|
||||
|
||||
if (direct === undefined) {
|
||||
return undefined
|
||||
}
|
||||
const result: (TagRenderingConfigJson & { id: string })[] = []
|
||||
for (const tagRenderingConfigJson of direct) {
|
||||
const nm: string | string[] | undefined = tagRenderingConfigJson["builtin"]
|
||||
if (nm !== undefined) {
|
||||
let indirect: TagRenderingConfigJson[]
|
||||
if (typeof nm === "string") {
|
||||
indirect = this.lookup(nm, ctx)
|
||||
} else {
|
||||
indirect = [].concat(...nm.map((n) => this.lookup(n, ctx)))
|
||||
}
|
||||
for (let foundTr of indirect) {
|
||||
foundTr = Utils.Clone<any>(foundTr)
|
||||
ctx.MergeObjectsForOverride(tagRenderingConfigJson["override"] ?? {}, foundTr)
|
||||
foundTr["id"] = tagRenderingConfigJson["id"] ?? foundTr["id"]
|
||||
result.push(<any>foundTr)
|
||||
}
|
||||
} else {
|
||||
result.push(tagRenderingConfigJson)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a tagRendering or group of tagRenderings based on the name.
|
||||
*/
|
||||
private directLookup(name: string): (TagRenderingConfigJson & { id: string })[] | undefined {
|
||||
const state = this._state
|
||||
if (state.tagRenderings.has(name)) {
|
||||
return [state.tagRenderings.get(name)]
|
||||
}
|
||||
if (this._tagRenderingsByLabel.has(name)) {
|
||||
return this._tagRenderingsByLabel.get(name)
|
||||
}
|
||||
|
||||
if (name.indexOf(".") < 0) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const spl = name.split(".")
|
||||
let layer = state.sharedLayers?.get(spl[0])
|
||||
if (spl[0] === this._self?.id) {
|
||||
layer = this._self
|
||||
}
|
||||
|
||||
if (spl.length !== 2 || !layer) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const id = spl[1]
|
||||
|
||||
const layerTrs = <(TagRenderingConfigJson & { id: string })[]>(
|
||||
layer.tagRenderings.filter((tr) => tr["id"] !== undefined)
|
||||
)
|
||||
let matchingTrs: (TagRenderingConfigJson & { id: string })[]
|
||||
if (id === "*") {
|
||||
matchingTrs = layerTrs
|
||||
} else if (id.startsWith("*")) {
|
||||
const id_ = id.substring(1)
|
||||
matchingTrs = layerTrs.filter((tr) => tr["labels"]?.indexOf(id_) >= 0)
|
||||
} else {
|
||||
matchingTrs = layerTrs.filter((tr) => tr["id"] === id || tr["labels"]?.indexOf(id) >= 0)
|
||||
}
|
||||
|
||||
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])
|
||||
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") {
|
||||
if (found.condition === undefined) {
|
||||
found.condition = layer.source["osmTags"]
|
||||
} else {
|
||||
found.condition = { and: [found.condition, layer.source["osmTags"]] }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
found = contextWriter.convertStrict(
|
||||
found,
|
||||
ConversionContext.construct(
|
||||
[layer.id, "tagRenderings", found["id"]],
|
||||
["AddContextToTranslations"],
|
||||
),
|
||||
)
|
||||
matchingTrs[i] = found
|
||||
}
|
||||
|
||||
if (matchingTrs.length !== 0) {
|
||||
return matchingTrs
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
private convertOnce(tr: string | any, ctx: ConversionContext): (TagRenderingConfigJson & { id: string })[] {
|
||||
const state = this._state
|
||||
|
||||
if (typeof tr === "string") {
|
||||
if (this._state.tagRenderings !== null) {
|
||||
const lookup = this.lookup(tr, ctx)
|
||||
if (lookup) {
|
||||
return lookup
|
||||
}
|
||||
}
|
||||
if (
|
||||
this._state.sharedLayers?.size > 0 &&
|
||||
ctx.path.at(-1) !== "icon" &&
|
||||
!ctx.path.find((p) => p === "pointRendering")
|
||||
) {
|
||||
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(", "),
|
||||
)
|
||||
}
|
||||
|
||||
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 +
|
||||
"`? ",
|
||||
)
|
||||
}
|
||||
|
||||
return [
|
||||
<any>{
|
||||
render: tr,
|
||||
id: tr.replace(/[^a-zA-Z0-9]/g, ""),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
if (tr["builtin"] !== undefined) {
|
||||
let names: string | string[] = tr["builtin"]
|
||||
if (typeof names === "string") {
|
||||
names = [names]
|
||||
}
|
||||
|
||||
if (this._state.tagRenderings === null) {
|
||||
return []
|
||||
}
|
||||
|
||||
for (const key of Object.keys(tr)) {
|
||||
if (
|
||||
key === "builtin" ||
|
||||
key === "override" ||
|
||||
key === "id" ||
|
||||
key.startsWith("#")
|
||||
) {
|
||||
continue
|
||||
}
|
||||
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),
|
||||
)
|
||||
}
|
||||
|
||||
const trs: (TagRenderingConfigJson & { id: string })[] = []
|
||||
for (const name of names) {
|
||||
const lookup = this.lookup(name, ctx)
|
||||
if (lookup === undefined) {
|
||||
let candidates = Array.from(state.tagRenderings.keys())
|
||||
if (name.indexOf(".") > 0) {
|
||||
const [layerName] = name.split(".")
|
||||
if (layerName === undefined) {
|
||||
ctx.err("Layername is undefined", name)
|
||||
}
|
||||
let layer = state.sharedLayers.get(layerName)
|
||||
if (layerName === this._self?.id) {
|
||||
layer = this._self
|
||||
}
|
||||
if (layer === undefined) {
|
||||
const candidates = Utils.sortedByLevenshteinDistance(
|
||||
layerName,
|
||||
Utils.NoNull(Array.from(state.sharedLayers.keys())),
|
||||
(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. ",
|
||||
)
|
||||
} else {
|
||||
ctx.err(
|
||||
": While reusing tagrendering: " +
|
||||
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,
|
||||
)
|
||||
}
|
||||
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",
|
||||
)
|
||||
continue
|
||||
}
|
||||
for (let foundTr of lookup) {
|
||||
foundTr = Utils.Clone<any>(foundTr)
|
||||
ctx.MergeObjectsForOverride(tr["override"] ?? {}, foundTr)
|
||||
if (names.length == 1) {
|
||||
foundTr["id"] = tr["id"] ?? foundTr["id"]
|
||||
}
|
||||
trs.push(foundTr)
|
||||
}
|
||||
}
|
||||
return trs
|
||||
}
|
||||
|
||||
return [tr]
|
||||
}
|
||||
}
|
|
@ -1,14 +1,4 @@
|
|||
import {
|
||||
Concat,
|
||||
Conversion,
|
||||
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 { Utils } from "../../../Utils"
|
||||
|
@ -17,7 +7,6 @@ import SpecialVisualizations from "../../../UI/SpecialVisualizations"
|
|||
import Translations from "../../../UI/i18n/Translations"
|
||||
import { Translation } from "../../../UI/i18n/Translation"
|
||||
import tagrenderingconfigmeta from "../../../../src/assets/schemas/tagrenderingconfigmeta.json"
|
||||
import { AddContextToTranslations } from "./AddContextToTranslations"
|
||||
import FilterConfigJson from "../Json/FilterConfigJson"
|
||||
import { TagConfigJson } from "../Json/TagConfigJson"
|
||||
import PointRenderingConfigJson, { IconConfigJson } from "../Json/PointRenderingConfigJson"
|
||||
|
@ -30,6 +19,7 @@ import { ConversionContext } from "./ConversionContext"
|
|||
import { ExpandRewrite } from "./ExpandRewrite"
|
||||
import { TagUtils } from "../../../Logic/Tags/TagUtils"
|
||||
import { ExpandFilter, PruneFilters } from "./ExpandFilter"
|
||||
import { ExpandTagRendering } from "./ExpandTagRendering"
|
||||
|
||||
class AddFiltersFromTagRenderings extends DesugaringStep<LayerConfigJson> {
|
||||
constructor() {
|
||||
|
@ -103,359 +93,6 @@ class AddFiltersFromTagRenderings extends DesugaringStep<LayerConfigJson> {
|
|||
}
|
||||
}
|
||||
|
||||
class ExpandTagRendering extends Conversion<
|
||||
| string
|
||||
| TagRenderingConfigJson
|
||||
| {
|
||||
builtin: string | string[]
|
||||
override: any
|
||||
},
|
||||
TagRenderingConfigJson[]
|
||||
> {
|
||||
private readonly _state: DesugaringContext
|
||||
private readonly _tagRenderingsByLabel: Map<string, TagRenderingConfigJson[]>
|
||||
// Only used for self-reference
|
||||
private readonly _self: LayerConfigJson
|
||||
private readonly _options: {
|
||||
/* If true, will copy the 'osmSource'-tags into the condition */
|
||||
applyCondition?: true | boolean
|
||||
noHardcodedStrings?: false | boolean
|
||||
addToContext?: false | boolean
|
||||
}
|
||||
|
||||
constructor(
|
||||
state: DesugaringContext,
|
||||
self: LayerConfigJson,
|
||||
options?: {
|
||||
applyCondition?: true | boolean
|
||||
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"
|
||||
)
|
||||
this._state = state
|
||||
this._self = self
|
||||
this._options = options
|
||||
this._tagRenderingsByLabel = new Map<string, TagRenderingConfigJson[]>()
|
||||
for (const trconfig of state.tagRenderings?.values() ?? []) {
|
||||
for (const label of trconfig["labels"] ?? []) {
|
||||
let withLabel = this._tagRenderingsByLabel.get(label)
|
||||
if (withLabel === undefined) {
|
||||
withLabel = []
|
||||
this._tagRenderingsByLabel.set(label, withLabel)
|
||||
}
|
||||
withLabel.push(trconfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public convert(
|
||||
spec: string | any,
|
||||
ctx: ConversionContext
|
||||
): QuestionableTagRenderingConfigJson[] {
|
||||
const trs = this.convertOnce(spec, ctx)
|
||||
const result = []
|
||||
if(!Array.isArray(trs)){
|
||||
ctx.err("Result of lookup for "+spec+" is not iterable; got "+trs)
|
||||
return undefined
|
||||
}
|
||||
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))
|
||||
result.push(...stable)
|
||||
if (this._options?.addToContext) {
|
||||
for (const tr of stable) {
|
||||
this._state.tagRenderings?.set(tr.id, tr)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result.push(tr)
|
||||
if (this._options?.addToContext) {
|
||||
this._state.tagRenderings?.set(tr["id"], <QuestionableTagRenderingConfigJson>tr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private pruneMappings(tagRendering: QuestionableTagRenderingConfigJson, ctx: ConversionContext): QuestionableTagRenderingConfigJson{
|
||||
if(!tagRendering["strict"]){
|
||||
return tagRendering
|
||||
}
|
||||
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 after = newMappings?.length ?? 0
|
||||
if(before - after > 0){
|
||||
ctx.info(`Pruned mappings for ${tagRendering.id}, from ${before} to ${after} (removed ${before - after})`)
|
||||
}
|
||||
const tr = {
|
||||
...tagRendering,
|
||||
mappings: newMappings
|
||||
}
|
||||
delete tr["strict"]
|
||||
return tr
|
||||
}
|
||||
|
||||
private lookup(name: string, ctx: ConversionContext): TagRenderingConfigJson[] | undefined {
|
||||
const direct = this.directLookup(name)
|
||||
|
||||
if (direct === undefined) {
|
||||
return undefined
|
||||
}
|
||||
const result: TagRenderingConfigJson[] = []
|
||||
for (const tagRenderingConfigJson of direct) {
|
||||
const nm: string | string[] | undefined = tagRenderingConfigJson["builtin"]
|
||||
if (nm !== undefined) {
|
||||
let indirect: TagRenderingConfigJson[]
|
||||
if (typeof nm === "string") {
|
||||
indirect = this.lookup(nm, ctx)
|
||||
} else {
|
||||
indirect = [].concat(...nm.map((n) => this.lookup(n, ctx)))
|
||||
}
|
||||
for (let foundTr of indirect) {
|
||||
foundTr = Utils.Clone<any>(foundTr)
|
||||
ctx.MergeObjectsForOverride(tagRenderingConfigJson["override"] ?? {}, foundTr)
|
||||
foundTr["id"] = tagRenderingConfigJson["id"] ?? foundTr["id"]
|
||||
result.push(foundTr)
|
||||
}
|
||||
} else {
|
||||
result.push(tagRenderingConfigJson)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a tagRendering or group of tagRenderings based on the name.
|
||||
*/
|
||||
private directLookup(name: string): TagRenderingConfigJson[] | undefined {
|
||||
const state = this._state
|
||||
if (state.tagRenderings.has(name)) {
|
||||
return [state.tagRenderings.get(name)]
|
||||
}
|
||||
if (this._tagRenderingsByLabel.has(name)) {
|
||||
return this._tagRenderingsByLabel.get(name)
|
||||
}
|
||||
|
||||
if (name.indexOf(".") < 0) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const spl = name.split(".")
|
||||
let layer = state.sharedLayers?.get(spl[0])
|
||||
if (spl[0] === this._self?.id) {
|
||||
layer = this._self
|
||||
}
|
||||
|
||||
if (spl.length !== 2 || !layer) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const id = spl[1]
|
||||
|
||||
const layerTrs = <TagRenderingConfigJson[]>(
|
||||
layer.tagRenderings.filter((tr) => tr["id"] !== undefined)
|
||||
)
|
||||
let matchingTrs: TagRenderingConfigJson[]
|
||||
if (id === "*") {
|
||||
matchingTrs = layerTrs
|
||||
} else if (id.startsWith("*")) {
|
||||
const id_ = id.substring(1)
|
||||
matchingTrs = layerTrs.filter((tr) => tr["labels"]?.indexOf(id_) >= 0)
|
||||
} else {
|
||||
matchingTrs = layerTrs.filter((tr) => tr["id"] === id || tr["labels"]?.indexOf(id) >= 0)
|
||||
}
|
||||
|
||||
const contextWriter = new AddContextToTranslations<TagRenderingConfigJson>("layers:")
|
||||
for (let i = 0; i < matchingTrs.length; i++) {
|
||||
let found: TagRenderingConfigJson = 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") {
|
||||
if (found.condition === undefined) {
|
||||
found.condition = layer.source["osmTags"]
|
||||
} else {
|
||||
found.condition = { and: [found.condition, layer.source["osmTags"]] }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
found = contextWriter.convertStrict(
|
||||
found,
|
||||
ConversionContext.construct(
|
||||
[layer.id, "tagRenderings", found["id"]],
|
||||
["AddContextToTranslations"]
|
||||
)
|
||||
)
|
||||
matchingTrs[i] = found
|
||||
}
|
||||
|
||||
if (matchingTrs.length !== 0) {
|
||||
return matchingTrs
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
private convertOnce(tr: string | any, ctx: ConversionContext): TagRenderingConfigJson[] {
|
||||
const state = this._state
|
||||
|
||||
if (typeof tr === "string") {
|
||||
if (this._state.tagRenderings !== null) {
|
||||
const lookup = this.lookup(tr, ctx)
|
||||
if(lookup){
|
||||
return lookup
|
||||
}
|
||||
}
|
||||
if (
|
||||
this._state.sharedLayers?.size > 0 &&
|
||||
ctx.path.at(-1) !== "icon" &&
|
||||
!ctx.path.find((p) => p === "pointRendering")
|
||||
) {
|
||||
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(", "),
|
||||
)
|
||||
}
|
||||
|
||||
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 +
|
||||
"`? ",
|
||||
)
|
||||
}
|
||||
|
||||
return [
|
||||
<any>{
|
||||
render: tr,
|
||||
id: tr.replace(/[^a-zA-Z0-9]/g, ""),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
if (tr["builtin"] !== undefined) {
|
||||
let names: string | string[] = tr["builtin"]
|
||||
if (typeof names === "string") {
|
||||
names = [names]
|
||||
}
|
||||
|
||||
if (this._state.tagRenderings === null) {
|
||||
return []
|
||||
}
|
||||
|
||||
for (const key of Object.keys(tr)) {
|
||||
if (
|
||||
key === "builtin" ||
|
||||
key === "override" ||
|
||||
key === "id" ||
|
||||
key.startsWith("#")
|
||||
) {
|
||||
continue
|
||||
}
|
||||
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)
|
||||
)
|
||||
}
|
||||
|
||||
const trs: TagRenderingConfigJson[] = []
|
||||
for (const name of names) {
|
||||
const lookup = this.lookup(name, ctx)
|
||||
if (lookup === undefined) {
|
||||
let candidates = Array.from(state.tagRenderings.keys())
|
||||
if (name.indexOf(".") > 0) {
|
||||
const [layerName] = name.split(".")
|
||||
if(layerName === undefined){
|
||||
ctx.err("Layername is undefined", name)
|
||||
}
|
||||
let layer = state.sharedLayers.get(layerName)
|
||||
if (layerName === this._self?.id) {
|
||||
layer = this._self
|
||||
}
|
||||
if (layer === undefined) {
|
||||
const candidates = Utils.sortedByLevenshteinDistance(
|
||||
layerName,
|
||||
Utils.NoNull(Array.from(state.sharedLayers.keys())),
|
||||
(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. "
|
||||
)
|
||||
} else {
|
||||
ctx.err(
|
||||
": While reusing tagrendering: " +
|
||||
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
|
||||
)
|
||||
}
|
||||
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"
|
||||
)
|
||||
continue
|
||||
}
|
||||
for (let foundTr of lookup) {
|
||||
foundTr = Utils.Clone<any>(foundTr)
|
||||
ctx.MergeObjectsForOverride(tr["override"] ?? {}, foundTr)
|
||||
if (names.length == 1) {
|
||||
foundTr["id"] = tr["id"] ?? foundTr["id"]
|
||||
}
|
||||
trs.push(foundTr)
|
||||
}
|
||||
}
|
||||
return trs
|
||||
}
|
||||
|
||||
return [tr]
|
||||
}
|
||||
}
|
||||
|
||||
class DetectInline extends DesugaringStep<QuestionableTagRenderingConfigJson> {
|
||||
constructor() {
|
||||
super(
|
||||
|
@ -1114,19 +751,19 @@ class ExpandMarkerRenderings extends DesugaringStep<IconConfigJson> {
|
|||
}
|
||||
|
||||
convert(json: IconConfigJson, context: ConversionContext): IconConfigJson {
|
||||
const expander = new ExpandTagRendering(this._state, this._layer)
|
||||
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
|
||||
} 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
|
||||
} else {
|
||||
result.color = json.color
|
||||
}
|
||||
|
|
|
@ -605,5 +605,5 @@ export interface LayerConfigJson {
|
|||
/**
|
||||
* group: hidden
|
||||
*/
|
||||
"#dont-translate": "*"
|
||||
"#dont-translate"?: "*"
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
import LoginToggle from "./Base/LoginToggle.svelte"
|
||||
import Pencil from "../assets/svg/Pencil.svelte"
|
||||
import Constants from "../Models/Constants"
|
||||
import { ImmutableStore, Store, Stores, UIEventSource } from "../Logic/UIEventSource"
|
||||
import { Store, Stores, UIEventSource } from "../Logic/UIEventSource"
|
||||
import ThemesList from "./BigComponents/ThemesList.svelte"
|
||||
import { MinimalThemeInformation } from "../Models/ThemeConfig/ThemeConfig"
|
||||
import Eye from "../assets/svg/Eye.svelte"
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import Marker from "../Map/Marker.svelte"
|
||||
import NextButton from "../Base/NextButton.svelte"
|
||||
import { AllKnownLayouts } from "../../Customizations/AllKnownLayouts"
|
||||
import { AllSharedLayers } from "../../Customizations/AllSharedLayers"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
|
||||
|
@ -19,7 +18,7 @@
|
|||
|
||||
function fetchIconDescription(layerId): any {
|
||||
if (category === "themes") {
|
||||
return AllKnownLayouts.allKnownLayouts.get(layerId).icon
|
||||
return undefined
|
||||
}
|
||||
return AllSharedLayers.getSharedLayersConfigs().get(layerId)?._layerIcon
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Utils } from "../../../src/Utils"
|
||||
import ThemeConfig from "../../../src/Models/ThemeConfig/ThemeConfig"
|
||||
|
||||
import * as bookcaseJson from "../../../src/assets/generated/themes/bookcases.json"
|
||||
import * as bookcaseJson from "../../../public/assets/generated/themes/bookcases.json"
|
||||
import { OsmTags } from "../../../src/Models/OsmFeature"
|
||||
import { Feature, Geometry } from "geojson"
|
||||
import { expect, it } from "vitest"
|
||||
|
|
|
@ -5,7 +5,7 @@ import ThemeConfig from "../../../../src/Models/ThemeConfig/ThemeConfig"
|
|||
import bookcaseLayer from "../../../../src/assets/generated/layers/public_bookcase.json"
|
||||
import LayerConfig from "../../../../src/Models/ThemeConfig/LayerConfig"
|
||||
import { ExtractImages } from "../../../../src/Models/ThemeConfig/Conversion/FixImages"
|
||||
import cyclofix from "../../../../src/assets/generated/themes/cyclofix.json"
|
||||
import cyclofix from "../../../../public/assets/generated/themes/cyclofix.json"
|
||||
import { Tag } from "../../../../src/Logic/Tags/Tag"
|
||||
import { DesugaringContext } from "../../../../src/Models/ThemeConfig/Conversion/Conversion"
|
||||
import { And } from "../../../../src/Logic/Tags/And"
|
||||
|
@ -68,6 +68,7 @@ describe("PrepareTheme", () => {
|
|||
tagRenderings: new Map<string, QuestionableTagRenderingConfigJson>(),
|
||||
sharedLayers,
|
||||
publicLayers: new Set<string>(),
|
||||
tagRenderingOrder: []
|
||||
})
|
||||
let themeConfigJsonPrepared = prepareStep.convertStrict(theme, ConversionContext.test())
|
||||
const themeConfig = new ThemeConfig(themeConfigJsonPrepared)
|
||||
|
@ -86,6 +87,7 @@ describe("PrepareTheme", () => {
|
|||
tagRenderings: new Map<string, QuestionableTagRenderingConfigJson>(),
|
||||
sharedLayers,
|
||||
publicLayers: new Set<string>(),
|
||||
tagRenderingOrder: [],
|
||||
}).convertStrict(themeConfigJson, ConversionContext.test())
|
||||
const themeConfig = new ThemeConfig(themeConfigJsonPrepared)
|
||||
const layerUnderTest = <LayerConfig>(
|
||||
|
@ -101,6 +103,7 @@ describe("PrepareTheme", () => {
|
|||
tagRenderings: new Map<string, QuestionableTagRenderingConfigJson>(),
|
||||
sharedLayers,
|
||||
publicLayers: new Set<string>(),
|
||||
tagRenderingOrder: [],
|
||||
}).convertStrict(
|
||||
{
|
||||
...themeConfigJson,
|
||||
|
@ -148,6 +151,7 @@ describe("PrepareTheme", () => {
|
|||
sharedLayers,
|
||||
tagRenderings: new Map<string, QuestionableTagRenderingConfigJson>(),
|
||||
publicLayers: new Set<string>(),
|
||||
tagRenderingOrder: []
|
||||
}
|
||||
const layout: ThemeConfigJson = {
|
||||
description: "A testing theme",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue