diff --git a/assets/layers/charging_station/csvToJson.ts b/assets/layers/charging_station/csvToJson.ts index c508835c6..4e620e7f1 100644 --- a/assets/layers/charging_station/csvToJson.ts +++ b/assets/layers/charging_station/csvToJson.ts @@ -5,6 +5,7 @@ import { LayerConfigJson } from "../../../src/Models/ThemeConfig/Json/LayerConfi import FilterConfigJson from "../../../src/Models/ThemeConfig/Json/FilterConfigJson" import RewritableConfigJson from "../../../src/Models/ThemeConfig/Json/RewritableConfigJson" import { TagRenderingConfigJson } from "../../../src/Models/ThemeConfig/Json/TagRenderingConfigJson" +import { Lists } from "../../../src/Utils/Lists" interface ChargingStandard { key: string, @@ -27,36 +28,36 @@ function colonSplit(value: string): string[] { } function loadCsv(file): ChargingStandard[] { - const entries: string[] = Utils.NoNull(readFileSync(file, "utf8").split("\n").map(str => str.trim())) + const entries: string[] = Lists.noNull(readFileSync(file, "utf8").split("\n").map(str => str.trim())) const header = entries.shift().split(",") - return Utils.NoNull(entries.map(entry => { - const values = entry.split(",").map(str => str.trim()) - if (values[0] === undefined || values[0] === "") { - return undefined + return Lists.noNull(entries.map(entry => { + const values = entry.split(",").map(str => str.trim()) + if (values[0] === undefined || values[0] === "") { + return undefined + } + + const v = {} + const colonSeperated = ["commonVoltages", "commonOutputs", "commonCurrents", "countryWhiteList", "countryBlackList", "associatedVehicleTypes", "neverAssociatedWith"] + const descriptionTranslations = new Map() + for (let j = 0; j < header.length; j++) { + const key = header[j] + if (key.startsWith("description")) { + const language = key.substring("description:".length) + descriptionTranslations.set(language, values[j]) } - const v = {} - const colonSeperated = ["commonVoltages", "commonOutputs", "commonCurrents", "countryWhiteList", "countryBlackList", "associatedVehicleTypes", "neverAssociatedWith"] - const descriptionTranslations = new Map() - for (let j = 0; j < header.length; j++) { - const key = header[j] - if (key.startsWith("description")) { - const language = key.substring("description:".length) - descriptionTranslations.set(language, values[j]) - } - - if (colonSeperated.indexOf(key) >= 0) { - v[key] = colonSplit(values[j]) - } else { - v[key] = values[j] - } + if (colonSeperated.indexOf(key) >= 0) { + v[key] = colonSplit(values[j]) + } else { + v[key] = values[j] } - v["description"] = descriptionTranslations - if (v["id"] === "") { - v["id"] = v["key"] - } - return v + } + v["description"] = descriptionTranslations + if (v["id"] === "") { + v["id"] = v["key"] + } + return v })) } @@ -161,7 +162,7 @@ function run(file, protojson) { // We add a second time for any amount to trigger a visualisation; but this is not an answer option const no_ask_json = { if: { - and: Utils.NoEmpty([`${e.key}~*`, `${e.key}!=1`, ...e.extraVisualisationCondition.split(";")]), + and: Lists.noEmpty([`${e.key}~*`, `${e.key}!=1`, ...e.extraVisualisationCondition.split(";")]), }, then: txt, hideInAnswer: true, diff --git a/assets/layers/id_presets/id_presets.json b/assets/layers/id_presets/id_presets.json index 964118847..38452189b 100644 --- a/assets/layers/id_presets/id_presets.json +++ b/assets/layers/id_presets/id_presets.json @@ -223,8 +223,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-tractor.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-tractor.svg" } }, { @@ -401,8 +401,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-wine-bottle.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-wine-bottle.svg" } }, { @@ -545,8 +545,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-dragon.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-dragon.svg" } }, { @@ -671,8 +671,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-furniture.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-furniture.svg" } }, { @@ -989,8 +989,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-laundry.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-laundry.svg" } }, { @@ -1149,8 +1149,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -1321,8 +1321,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-baby-carriage.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-baby-carriage.svg" } }, { @@ -1494,8 +1494,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-suitcase-rolling.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-suitcase-rolling.svg" } }, { @@ -1655,8 +1655,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-bakery.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-bakery.svg" } }, { @@ -1786,8 +1786,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-bath.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-bath.svg" } }, { @@ -1976,8 +1976,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-lipstick.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-lipstick.svg" } }, { @@ -2160,8 +2160,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-lodging.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-lodging.svg" } }, { @@ -2298,8 +2298,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-bottles.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-bottles.svg" } }, { @@ -2472,8 +2472,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-bicycle.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-bicycle.svg" } }, { @@ -2649,8 +2649,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-boat.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-boat.svg" } }, { @@ -2814,8 +2814,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-money_hand.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-money_hand.svg" } }, { @@ -2924,8 +2924,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-book.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-book.svg" } }, { @@ -3056,8 +3056,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-storage_fermenter.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-storage_fermenter.svg" } }, { @@ -3213,8 +3213,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-cleaver.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-cleaver.svg" } }, { @@ -3352,8 +3352,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-camera-retro.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-camera-retro.svg" } }, { @@ -3496,8 +3496,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-burn.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-burn.svg" } }, { @@ -3643,8 +3643,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-cannabis.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-cannabis.svg" } }, { @@ -3797,8 +3797,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-car_dealer.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-car_dealer.svg" } }, { @@ -3948,8 +3948,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-car-battery.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-car-battery.svg" } }, { @@ -4159,8 +4159,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-car-repair.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-car-repair.svg" } }, { @@ -4297,8 +4297,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-camper_trailer.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-camper_trailer.svg" } }, { @@ -4427,8 +4427,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-tape.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-tape.svg" } }, { @@ -4522,8 +4522,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -4654,8 +4654,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -4782,8 +4782,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-cheese.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-cheese.svg" } }, { @@ -4976,8 +4976,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-shopping-basket.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-shopping-basket.svg" } }, { @@ -5113,8 +5113,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-confectionery.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-confectionery.svg" } }, { @@ -5342,8 +5342,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-clothing-store.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-clothing-store.svg" } }, { @@ -5478,8 +5478,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-coffee.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-coffee.svg" } }, { @@ -5684,8 +5684,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-th.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-th.svg" } }, { @@ -5839,8 +5839,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-laptop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-laptop.svg" } }, { @@ -6028,8 +6028,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-confectionery.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-confectionery.svg" } }, { @@ -6192,8 +6192,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-shopping-basket.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-shopping-basket.svg" } }, { @@ -6340,8 +6340,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-print.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-print.svg" } }, { @@ -6483,8 +6483,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-lipstick.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-lipstick.svg" } }, { @@ -6576,8 +6576,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-hat-cowboy-side.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-hat-cowboy-side.svg" } }, { @@ -6740,8 +6740,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-cut.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-cut.svg" } }, { @@ -6891,8 +6891,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-curtains.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-curtains.svg" } }, { @@ -7058,8 +7058,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-cheese.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-cheese.svg" } }, { @@ -7171,8 +7171,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-jar.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-jar.svg" } }, { @@ -7300,8 +7300,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -7482,8 +7482,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-tools.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-tools.svg" } }, { @@ -7597,8 +7597,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-door-open.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-door-open.svg" } }, { @@ -7713,8 +7713,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-clothes_hanger.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-clothes_hanger.svg" } }, { @@ -7858,8 +7858,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -8032,8 +8032,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-power.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-power.svg" } }, { @@ -8257,8 +8257,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-plug.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-plug.svg" } }, { @@ -8418,8 +8418,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -8558,8 +8558,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-tape.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-tape.svg" } }, { @@ -8743,8 +8743,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-apple-alt.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-apple-alt.svg" } }, { @@ -8962,8 +8962,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-fashion_accessories.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-fashion_accessories.svg" } }, { @@ -9108,8 +9108,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-fireplace.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-fireplace.svg" } }, { @@ -9290,8 +9290,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-ice_fishing.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-ice_fishing.svg" } }, { @@ -9411,8 +9411,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-tools.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-tools.svg" } }, { @@ -9543,8 +9543,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-florist.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-florist.svg" } }, { @@ -9691,8 +9691,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-vector-square.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-vector-square.svg" } }, { @@ -9821,8 +9821,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-snowflake.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-snowflake.svg" } }, { @@ -10019,8 +10019,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-propane_tank.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-propane_tank.svg" } }, { @@ -10184,8 +10184,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-cemetery.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-cemetery.svg" } }, { @@ -10352,8 +10352,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-couch.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-couch.svg" } }, { @@ -10535,8 +10535,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-dice.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-dice.svg" } }, { @@ -10692,8 +10692,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-garden-centre.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-garden-centre.svg" } }, { @@ -10892,8 +10892,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-propane_tank.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-propane_tank.svg" } }, { @@ -11008,8 +11008,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -11169,8 +11169,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-gift.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-gift.svg" } }, { @@ -11373,8 +11373,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-carrot.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-carrot.svg" } }, { @@ -11557,8 +11557,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-beauty_salon.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-beauty_salon.svg" } }, { @@ -11707,8 +11707,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-hair_care.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-hair_care.svg" } }, { @@ -11883,8 +11883,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-tools.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-tools.svg" } }, { @@ -12048,8 +12048,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -12198,8 +12198,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-hearing_aid.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-hearing_aid.svg" } }, { @@ -12346,8 +12346,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-leaf.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-leaf.svg" } }, { @@ -12502,8 +12502,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-speaker.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-speaker.svg" } }, { @@ -12581,8 +12581,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -12821,8 +12821,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-cloth.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-cloth.svg" } }, { @@ -12985,8 +12985,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-blender.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-blender.svg" } }, { @@ -13160,8 +13160,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-bow_and_arrow.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-bow_and_arrow.svg" } }, { @@ -13324,8 +13324,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -13578,8 +13578,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-jewelry-store.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-jewelry-store.svg" } }, { @@ -13743,8 +13743,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-store.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-store.svg" } }, { @@ -13872,8 +13872,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-kitchen_sink.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-kitchen_sink.svg" } }, { @@ -13994,8 +13994,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-laundry.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-laundry.svg" } }, { @@ -14133,8 +14133,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-handbag.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-handbag.svg" } }, { @@ -14303,8 +14303,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-desk_lamp.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-desk_lamp.svg" } }, { @@ -14466,8 +14466,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-key.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-key.svg" } }, { @@ -14611,8 +14611,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-ticket-alt.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-ticket-alt.svg" } }, { @@ -14738,8 +14738,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-shopping_mall.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-shopping_mall.svg" } }, { @@ -14875,8 +14875,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-spa.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-spa.svg" } }, { @@ -15019,8 +15019,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-crutch.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-crutch.svg" } }, { @@ -15185,8 +15185,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-military.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-military.svg" } }, { @@ -15330,8 +15330,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-mobile-alt.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-mobile-alt.svg" } }, { @@ -15486,8 +15486,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -15636,8 +15636,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-money_hand.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-money_hand.svg" } }, { @@ -15773,8 +15773,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-motorcycle.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-motorcycle.svg" } }, { @@ -15939,8 +15939,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-motorcycle_repair.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-motorcycle_repair.svg" } }, { @@ -16104,8 +16104,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-compact-disc.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-compact-disc.svg" } }, { @@ -16263,8 +16263,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-guitar.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-guitar.svg" } }, { @@ -16379,8 +16379,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-newspaper.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-newspaper.svg" } }, { @@ -16518,8 +16518,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-pills.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-pills.svg" } }, { @@ -16700,8 +16700,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -16863,8 +16863,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-optician.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-optician.svg" } }, { @@ -17046,8 +17046,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-compass.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-compass.svg" } }, { @@ -17167,8 +17167,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -17298,8 +17298,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-paint-roller.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-paint-roller.svg" } }, { @@ -17462,8 +17462,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-balloon.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-balloon.svg" } }, { @@ -17565,8 +17565,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-plate-wheat.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-plate-wheat.svg" } }, { @@ -17724,8 +17724,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-bakery.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-bakery.svg" } }, { @@ -17820,8 +17820,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-money_hand.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-money_hand.svg" } }, { @@ -17957,8 +17957,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-perfume.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-perfume.svg" } }, { @@ -18128,8 +18128,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-cat.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-cat.svg" } }, { @@ -18267,8 +18267,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-pet_grooming.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-pet_grooming.svg" } }, { @@ -18450,8 +18450,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-camera-retro.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-camera-retro.svg" } }, { @@ -18569,8 +18569,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-vase.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-vase.svg" } }, { @@ -18699,8 +18699,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-print.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-print.svg" } }, { @@ -18875,8 +18875,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-psychic.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-psychic.svg" } }, { @@ -19034,8 +19034,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-rocket_firework.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-rocket_firework.svg" } }, { @@ -19186,8 +19186,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-microchip.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-microchip.svg" } }, { @@ -19330,8 +19330,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -19449,8 +19449,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-dolly.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-dolly.svg" } }, { @@ -19577,8 +19577,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-tools.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-tools.svg" } }, { @@ -19649,8 +19649,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-bowl-rice.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-bowl-rice.svg" } }, { @@ -19807,8 +19807,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-scuba_diving.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-scuba_diving.svg" } }, { @@ -19979,8 +19979,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-fish_cleaning.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-fish_cleaning.svg" } }, { @@ -20106,8 +20106,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -20286,8 +20286,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-needle_and_spool.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-needle_and_spool.svg" } }, { @@ -20417,8 +20417,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-hammer_shoe.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-hammer_shoe.svg" } }, { @@ -20581,8 +20581,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shoe.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shoe.svg" } }, { @@ -20813,8 +20813,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-spice_bottle.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-spice_bottle.svg" } }, { @@ -20966,8 +20966,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-futbol.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-futbol.svg" } }, { @@ -21133,8 +21133,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-paperclip.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-paperclip.svg" } }, { @@ -21310,8 +21310,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-storage_rental.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-storage_rental.svg" } }, { @@ -21496,8 +21496,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-grocery.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-grocery.svg" } }, { @@ -21649,8 +21649,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-swimmer.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-swimmer.svg" } }, { @@ -21816,8 +21816,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-needle_and_spool.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-needle_and_spool.svg" } }, { @@ -21940,8 +21940,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-tattoo_machine.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-tattoo_machine.svg" } }, { @@ -22070,8 +22070,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-teahouse.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-teahouse.svg" } }, { @@ -22207,8 +22207,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-telephone.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-telephone.svg" } }, { @@ -22358,8 +22358,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-ticket-alt.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-ticket-alt.svg" } }, { @@ -22500,8 +22500,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-tiling.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-tiling.svg" } }, { @@ -22681,8 +22681,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-pipe.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-pipe.svg" } }, { @@ -22777,8 +22777,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-tools.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-tools.svg" } }, { @@ -22908,8 +22908,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-rocket.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-rocket.svg" } }, { @@ -23086,8 +23086,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-tools.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-tools.svg" } }, { @@ -23235,8 +23235,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-suitcase.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-suitcase.svg" } }, { @@ -23407,8 +23407,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-trophy.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-trophy.svg" } }, { @@ -23542,8 +23542,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-tire.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-tire.svg" } }, { @@ -23668,8 +23668,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-vacuum.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-vacuum.svg" } }, { @@ -23793,8 +23793,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -23943,8 +23943,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-movie_rental.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-movie_rental.svg" } }, { @@ -24102,8 +24102,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-gaming.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-gaming.svg" } }, { @@ -24258,8 +24258,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-watch.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-watch.svg" } }, { @@ -24382,8 +24382,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-water_bottle.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-water_bottle.svg" } }, { @@ -24550,8 +24550,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/fas-swimmer.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/fas-swimmer.svg" } }, { @@ -24724,8 +24724,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-dagger.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-dagger.svg" } }, { @@ -24834,8 +24834,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-warehouse.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-warehouse.svg" } }, { @@ -24972,8 +24972,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-shop.svg" } }, { @@ -25113,8 +25113,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-window.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/temaki-window.svg" } }, { @@ -25275,8 +25275,8 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/maki-alcohol-shop.svg", - "class": "medium" + "class": "medium", + "path": "./assets/layers/id_presets/maki-alcohol-shop.svg" } } ] diff --git a/assets/layers/tree/tree.json b/assets/layers/tree/tree.json index 7959b01b9..53599d19b 100644 --- a/assets/layers/tree/tree.json +++ b/assets/layers/tree/tree.json @@ -943,9 +943,9 @@ "ru": "Onroerend Erfgoed ID:" }, "special": { - "type": "link", "href": "https://id.erfgoed.net/erfgoedobjecten/{ref:OnroerendErfgoed}", - "text": "{ref:OnroerendErfgoed}" + "text": "{ref:OnroerendErfgoed}", + "type": "link" } }, "icon": "./assets/layers/tree/Onroerend_Erfgoed_logo_without_text.svg", diff --git a/scripts/GenerateSeries.ts b/scripts/GenerateSeries.ts index 5775cbf16..f966b47ac 100644 --- a/scripts/GenerateSeries.ts +++ b/scripts/GenerateSeries.ts @@ -103,13 +103,13 @@ class StatsDownloader { let page = 1 let allFeatures: ChangeSetData[] = [] const endDay = new Date(year, month - 1 /* Zero-indexed: 0 = january*/, day + 1) - const endDate = `${endDay.getFullYear()}-${Utils.TwoDigits( + const endDate = `${endDay.getFullYear()}-${Utils.twoDigits( endDay.getMonth() + 1 - )}-${Utils.TwoDigits(endDay.getDate())}` + )}-${Utils.twoDigits(endDay.getDate())}` let url = this.urlTemplate .replace( "{start_date}", - year + "-" + Utils.TwoDigits(month) + "-" + Utils.TwoDigits(day) + year + "-" + Utils.twoDigits(month) + "-" + Utils.twoDigits(day) ) .replace("{end_date}", endDate) .replace("{page}", "" + page) @@ -142,7 +142,7 @@ class StatsDownloader { } url = result.next } - allFeatures = Utils.NoNull(allFeatures) + allFeatures = Lists.noNull(allFeatures) allFeatures.forEach((f) => { f.properties = { ...f.properties, ...f.properties.metadata } if (f.properties.editor.toLowerCase().indexOf("android") >= 0) { diff --git a/scripts/fetchLanguages.ts b/scripts/fetchLanguages.ts index e01558500..8f58b3805 100644 --- a/scripts/fetchLanguages.ts +++ b/scripts/fetchLanguages.ts @@ -9,6 +9,7 @@ import { existsSync, readFileSync, writeFileSync } from "fs" import WikidataUtils from "../src/Utils/WikidataUtils" import LanguageUtils from "../src/Utils/LanguageUtils" import Wikidata from "../src/Logic/Web/Wikidata" +import { Lists } from "../src/Utils/Lists" interface value { value: T @@ -196,7 +197,7 @@ async function main(wipeCache = false) { }) translatedForId["_meta"] = { - countries: Utils.Dedup(languagesPerCountry[key]), + countries: Lists.dedup(languagesPerCountry[key]), dir: value.directionality, } diff --git a/scripts/fixSchemas.ts b/scripts/fixSchemas.ts index efbd7e542..942d1bc2b 100644 --- a/scripts/fixSchemas.ts +++ b/scripts/fixSchemas.ts @@ -7,6 +7,7 @@ import Validators from "../src/UI/InputElement/Validators" import { AllKnownLayouts } from "../src/Customizations/AllKnownLayouts" import { AllSharedLayers } from "../src/Customizations/AllSharedLayers" import Constants from "../src/Models/Constants" +import { Lists } from "../src/Utils/Lists" const metainfo = { type: "One of the inputValidator types", @@ -371,7 +372,7 @@ function extractMeta( const fullPath = "./src/assets/schemas/" + path + ".json" writeFileSync(fullPath, JSON.stringify(paths, null, " ")) console.log("Written meta to " + fullPath) - return Utils.NoNull(paths.map((p) => validateMeta(p))) + return Lists.noNull(paths.map((p) => validateMeta(p))) } function main() { diff --git a/scripts/generateDocs.ts b/scripts/generateDocs.ts index caba971d7..a15768a1d 100644 --- a/scripts/generateDocs.ts +++ b/scripts/generateDocs.ts @@ -34,6 +34,7 @@ import { ImmutableStore } from "../src/Logic/UIEventSource" import * as unitUsage from "../Docs/Schemas/UnitConfigJson.schema.json" import { ThemeConfigJson } from "../src/Models/ThemeConfig/Json/ThemeConfigJson" import { ServerSourceInfo, SourceOverview } from "../src/Models/SourceOverview" +import { Lists } from "../src/Utils/Lists" /** * Converts a markdown-file into a .json file, which a walkthrough/slideshow element can use @@ -562,7 +563,7 @@ export class GenerateDocs extends Script { ) ) const serverInfos = Utils.DedupOnId(serverInfosDupl, (item) => item.url) - const titles = Utils.Dedup(Utils.NoEmpty(serverInfos.map((s) => s.category))) + const titles = Lists.dedup(Lists.noEmpty(serverInfos.map((s) => s.category))) titles.sort() function getHost(item: ServerSourceInfo) { @@ -597,7 +598,7 @@ export class GenerateDocs extends Script { md.push(items.length + " items") md.push(categoryExplanation[title]) - const hosts = Utils.Dedup(items.map(getHost)) + const hosts = Lists.dedup(items.map(getHost)) hosts.sort() if (title === "maplayer") { md.push(MarkdownUtils.list(hosts)) @@ -636,7 +637,7 @@ export class GenerateDocs extends Script { return [ item.url, identicalDescription ? "" : item.description, - Utils.NoEmpty([ + Lists.noEmpty([ item.openData ? "OpenData" : "", sourceAvailable, selfHostable, @@ -720,9 +721,7 @@ export class GenerateDocs extends Script { MarkdownUtils.list( Constants.priviliged_layers.map((id) => "[" + id + "](#" + id + ")") ), - ...Utils.NoNull( - Constants.priviliged_layers.map((id) => AllSharedLayers.sharedLayers.get(id)) - ).map((l) => + ...Lists.noNull(Constants.priviliged_layers.map((id) => AllSharedLayers.sharedLayers.get(id))).map((l) => l.generateDocumentation({ usedInThemes: themesPerLayer.get(l.id), layerIsNeededBy: layerIsNeededBy, diff --git a/scripts/generateFavouritesLayer.ts b/scripts/generateFavouritesLayer.ts index f6e446894..8caf4a798 100644 --- a/scripts/generateFavouritesLayer.ts +++ b/scripts/generateFavouritesLayer.ts @@ -13,6 +13,7 @@ import { TagUtils } from "../src/Logic/Tags/TagUtils" import { TagRenderingConfigJson } from "../src/Models/ThemeConfig/Json/TagRenderingConfigJson" import { Translatable } from "../src/Models/ThemeConfig/Json/Translatable" import * as questions from "../assets/layers/questions/questions.json" +import { Lists } from "../src/Utils/Lists" export class GenerateFavouritesLayer extends Script { private readonly layers: LayerConfigJson[] = [] @@ -155,7 +156,7 @@ export class GenerateFavouritesLayer extends Script { continue } newTr.condition = { - and: Utils.NoNull([newTr.condition, layerConfig.source["osmTags"]]), + and: Lists.noNull([newTr.condition, layerConfig.source["osmTags"]]), } generatedTagRenderings.push(newTr) blacklistedIds.add(newTr.id) diff --git a/scripts/generateLayerOverview.ts b/scripts/generateLayerOverview.ts index d8543e465..503c50454 100644 --- a/scripts/generateLayerOverview.ts +++ b/scripts/generateLayerOverview.ts @@ -37,10 +37,8 @@ import { Translatable } from "../src/Models/ThemeConfig/Json/Translatable" import { ValidateThemeAndLayers } from "../src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers" import { ExtractImages } from "../src/Models/ThemeConfig/Conversion/FixImages" import { TagRenderingConfigJson } from "../src/Models/ThemeConfig/Json/TagRenderingConfigJson" -import { - LayerConfigDependencyGraph, - LevelInfo, -} from "../src/Models/ThemeConfig/LayerConfigDependencyGraph" +import { LayerConfigDependencyGraph, LevelInfo } from "../src/Models/ThemeConfig/LayerConfigDependencyGraph" +import { Lists } from "../src/Utils/Lists" // This scripts scans 'src/assets/layers/*.json' for layer definition files and 'src/assets/themes/*.json' for theme definition files. // It spits out an overview of those to be used to load them @@ -126,20 +124,18 @@ class AddIconSummary extends DesugaringStep<{ raw: LayerConfigJson; parsed: Laye pr.location.has("point") ) const defaultTags = layerConfig.baseTags - fixed["_layerIcon"] = Utils.NoNull( - (pointRendering?.marker ?? []).map((i) => { - const icon = i.icon?.GetRenderValue(defaultTags)?.txt - if (!icon) { - return undefined - } - const result = { icon } - const c = i.color?.GetRenderValue(defaultTags)?.txt - if (c) { - result["color"] = c - } - return result - }) - ) + fixed["_layerIcon"] = Lists.noNull((pointRendering?.marker ?? []).map((i) => { + const icon = i.icon?.GetRenderValue(defaultTags)?.txt + if (!icon) { + return undefined + } + const result = { icon } + const c = i.color?.GetRenderValue(defaultTags)?.txt + if (c) { + result["color"] = c + } + return result + })) return { raw: fixed, parsed: layerConfig } } } @@ -233,7 +229,7 @@ class LayerBuilder extends Conversion> { const origIds: ReadonlyArray = [...ids] const deps = this._dependencies - const allDeps = Utils.Dedup([].concat(...ids.map((id) => deps.get(id)))) + const allDeps = Lists.dedup([].concat(...ids.map((id) => deps.get(id)))) const depsRecord = Utils.asRecord(Array.from(deps.keys()), (k) => deps.get(k).filter((dep) => ids.indexOf(dep) >= 0) ) @@ -864,7 +860,7 @@ class LayerOverviewUtils extends Script { ) } if(printAssets){ - const images = Utils.Dedup(Array.from(sharedThemes.values()).flatMap(th => th._usedImages ?? [] )) + const images = Lists.dedup(Array.from(sharedThemes.values()).flatMap(th => th._usedImages ?? [])) writeFileSync("needed_assets.csv", images.join("\n")) console.log("Written needed_assets.csv") } @@ -1278,11 +1274,9 @@ class LayerOverviewUtils extends Script { } } - const usedImages = Utils.Dedup( - new ExtractImages(true, knownTagRenderings) - .convertStrict(themeFile) - .map((x) => x.path) - ) + const usedImages = Lists.dedup(new ExtractImages(true, knownTagRenderings) + .convertStrict(themeFile) + .map((x) => x.path)) usedImages.sort() themeFile["_usedImages"] = usedImages diff --git a/scripts/generateLicenseInfo.ts b/scripts/generateLicenseInfo.ts index 04cf7fdea..2f3ff3f46 100644 --- a/scripts/generateLicenseInfo.ts +++ b/scripts/generateLicenseInfo.ts @@ -3,6 +3,7 @@ import SmallLicense from "../src/Models/smallLicense" import ScriptUtils from "./ScriptUtils" import Script from "./Script" import { Utils } from "../src/Utils" +import { Lists } from "../src/Utils/Lists" const prompt = require("prompt-sync")() @@ -297,9 +298,7 @@ export class GenerateLicenseInfo extends Script { sources: license.sources, } - cloned.license = Utils.Dedup( - cloned.license.split(";").map((l) => this.toSPDXCompliantLicense(l)) - ).join("; ") + cloned.license = Lists.dedup(cloned.license.split(";").map((l) => this.toSPDXCompliantLicense(l))).join("; ") if (cloned.license === "CC0-1.0; TRIVIAL") { cloned.license = "TRIVIAL" } diff --git a/scripts/generateNsiStats.ts b/scripts/generateNsiStats.ts index 720eac34d..a14a02413 100644 --- a/scripts/generateNsiStats.ts +++ b/scripts/generateNsiStats.ts @@ -10,6 +10,7 @@ import Script from "./Script" import NameSuggestionIndex from "../src/Logic/Web/NameSuggestionIndex" import TagInfo from "../src/Logic/Web/TagInfo" import { TagsFilter } from "../src/Logic/Tags/TagsFilter" +import { Lists } from "../src/Utils/Lists" class GenerateNsiStats extends Script { async createOptimizationFile(includeTags = true) { @@ -139,9 +140,7 @@ class GenerateNsiStats extends Script { ) } const nsi = await NameSuggestionIndex.singleton() - const allBrandNames: string[] = Utils.Dedup( - nsi.allPossible(type).map((item) => item.tags[type]) - ) + const allBrandNames: string[] = Lists.dedup(nsi.allPossible(type).map((item) => item.tags[type])) const batchSize = 50 for (let i = 0; i < allBrandNames.length; i += batchSize) { console.warn( @@ -152,7 +151,7 @@ class GenerateNsiStats extends Script { ) let downloaded = 0 await Promise.all( - Utils.TimesT(batchSize, async (j) => { + Utils.timesT(batchSize, async (j) => { const brand = allBrandNames[i + j] if (!allBrands[brand]) { allBrands[brand] = {} diff --git a/scripts/generateTaginfoProjectFiles.ts b/scripts/generateTaginfoProjectFiles.ts index 7e3be2a50..56dbb3a5f 100644 --- a/scripts/generateTaginfoProjectFiles.ts +++ b/scripts/generateTaginfoProjectFiles.ts @@ -5,6 +5,7 @@ import { readFileSync, writeFileSync } from "fs" import ThemeConfig from "../src/Models/ThemeConfig/ThemeConfig" import LayerConfig from "../src/Models/ThemeConfig/LayerConfig" import { Utils } from "../src/Utils" +import { Lists } from "../src/Utils/Lists" /** * Generates all the files in "Docs/TagInfo". These are picked up by the taginfo project, showing a link to the mapcomplete theme if the key is used @@ -269,7 +270,7 @@ function main() { } files.push(generateTagInfoEntry(layout)) } - generateProjectsOverview(Utils.NoNull(files)) + generateProjectsOverview(Lists.noNull(files)) } main() diff --git a/scripts/generateTranslations.ts b/scripts/generateTranslations.ts index fdd3306a3..489a93d7a 100644 --- a/scripts/generateTranslations.ts +++ b/scripts/generateTranslations.ts @@ -4,6 +4,7 @@ import { Utils } from "../src/Utils" import ScriptUtils from "./ScriptUtils" import Script from "./Script" import Constants from "../src/Models/Constants" +import { Lists } from "../src/Utils/Lists" const knownLanguages = ["en", "nl", "de", "fr", "es", "gl", "ca"] const ignoreTerms = ["searchTerms"] @@ -172,7 +173,7 @@ class TranslationPart { languages.push(...(value as TranslationPart).knownLanguages()) } } - return Utils.Dedup(languages) + return Lists.dedup(languages) } toJson(neededLanguage?: string): string { @@ -351,7 +352,7 @@ function transformTranslation( } const values: string[] = [] - const spaces = Utils.Times((_) => " ", path.length + 1) + const spaces = Utils.times((_) => " ", path.length + 1) for (const key in obj) { if (key === "#") { @@ -381,7 +382,7 @@ function transformTranslation( let expr = `new Translation(${JSON.stringify(value)}, "core:${path.join(".")}.${key}")` if (subParts !== null) { // convert '{to_substitute}' into 'to_substitute' - const types = Utils.Dedup(subParts.map((tp) => tp.substring(1, tp.length - 1))) + const types = Lists.dedup(subParts.map((tp) => tp.substring(1, tp.length - 1))) const invalid = types.filter( (part) => part.match(/^[a-z0-9A-Z_]+(\(.*\))?$/) == null ) @@ -764,7 +765,7 @@ class GenerateTranslations extends Script { "themes" ) - const usedLanguages: string[] = Utils.Dedup(l1.concat(l2)).filter((v) => v !== "*") + const usedLanguages: string[] = Lists.dedup(l1.concat(l2)).filter((v) => v !== "*") usedLanguages.sort() fs.writeFileSync( "./src/assets/used_languages.json", diff --git a/scripts/nsiLogos.ts b/scripts/nsiLogos.ts index 22dba7bc7..aa109a784 100644 --- a/scripts/nsiLogos.ts +++ b/scripts/nsiLogos.ts @@ -128,7 +128,7 @@ class NsiLogos extends Script { } const results = await Promise.all( - Utils.TimesT(stepcount, (j) => j).map(async (j) => { + Utils.timesT(stepcount, (j) => j).map(async (j) => { return await this.downloadLogo(items[i + j], type, basePath, alreadyDownloaded) }) ) diff --git a/scripts/velopark/diffToCsv.ts b/scripts/velopark/diffToCsv.ts index c5c883734..0cf86857b 100644 --- a/scripts/velopark/diffToCsv.ts +++ b/scripts/velopark/diffToCsv.ts @@ -1,7 +1,7 @@ import Script from "../Script" import { readFileSync, writeFileSync } from "fs" import { OsmId } from "../../src/Models/OsmFeature" -import { Utils } from "../../src/Utils" +import { Lists } from "../../src/Utils/Lists" interface DiffItem { /** @@ -34,7 +34,7 @@ export class DiffToCsv extends Script { JSON.parse(readFileSync(file, "utf8")) ) const diffs = json.diffs - const allKeys = Utils.Dedup(diffs.flatMap((item) => item.diffs.map((d) => d.key))) + const allKeys = Lists.dedup(diffs.flatMap((item) => item.diffs.map((d) => d.key))) allKeys.sort() const header = [ diff --git a/scripts/velopark/veloParkToGeojson.ts b/scripts/velopark/veloParkToGeojson.ts index 1487f3472..80e9c268d 100644 --- a/scripts/velopark/veloParkToGeojson.ts +++ b/scripts/velopark/veloParkToGeojson.ts @@ -74,7 +74,7 @@ class VeloParkToGeojson extends Script { const batchSize = 50 for (let i = 0; i < allVeloparkRaw.length; i += batchSize) { await Promise.all( - Utils.TimesT(batchSize, (j) => j).map(async (j) => { + Utils.timesT(batchSize, (j) => j).map(async (j) => { const f = allVeloparkRaw[i + j] if (!f) { return diff --git a/src/Logic/Actors/TitleHandler.ts b/src/Logic/Actors/TitleHandler.ts index bb4f70ca5..fb39a77b1 100644 --- a/src/Logic/Actors/TitleHandler.ts +++ b/src/Logic/Actors/TitleHandler.ts @@ -3,6 +3,7 @@ import Locale from "../../UI/i18n/Locale" import { Utils } from "../../Utils" import { Feature } from "geojson" import { SpecialVisualizationState } from "../../UI/SpecialVisualization" +import { Lists } from "../../Utils/Lists" export default class TitleHandler { constructor(selectedElement: Store, state: SpecialVisualizationState) { @@ -22,7 +23,7 @@ export default class TitleHandler { if (layer.title === undefined) { return defaultTitle } - const toRender = Utils.NoNull(layer?.title?.GetRenderValues(tags)) + const toRender = Lists.noNull(layer?.title?.GetRenderValues(tags)) const titleUnsubbed = toRender[0]?.then?.textFor(lng) if (titleUnsubbed === undefined) { return defaultTitle diff --git a/src/Logic/DetermineTheme.ts b/src/Logic/DetermineTheme.ts index 8db8829b3..31eabac30 100644 --- a/src/Logic/DetermineTheme.ts +++ b/src/Logic/DetermineTheme.ts @@ -17,6 +17,7 @@ import { ThemeConfigJson } from "../Models/ThemeConfig/Json/ThemeConfigJson" import { ValidateThemeAndLayers } from "../Models/ThemeConfig/Conversion/ValidateThemeAndLayers" import * as theme_overview from "../assets/generated/theme_overview.json" import * as favourite_layer from "../../assets/layers/favourite/favourite.json" +import { Lists } from "../Utils/Lists" export default class DetermineTheme { private static readonly _knownImages = new Set(Array.from(licenses).map((l) => l.path)) private static readonly loadCustomThemeParam = QueryParameters.GetQueryParameter( @@ -143,27 +144,25 @@ export default class DetermineTheme { if (json.layers === undefined && json.tagRenderings !== undefined) { // We got fed a layer instead of a theme const layerConfig = json - let icon = Utils.NoNull( - layerConfig.pointRendering - .flatMap((pr) => pr.marker) - .map((iconSpec) => { - if (!iconSpec) { - return undefined - } - const icon = new TagRenderingConfig(iconSpec.icon) - .render.txt - if ( - iconSpec.color === undefined || - icon.startsWith("http:") || - icon.startsWith("https:") - ) { - return icon - } - const color = new TagRenderingConfig(iconSpec.color) - .render.txt - return icon + ":" + color - }) - ).join(";") + let icon = Lists.noNull(layerConfig.pointRendering + .flatMap((pr) => pr.marker) + .map((iconSpec) => { + if (!iconSpec) { + return undefined + } + const icon = new TagRenderingConfig(iconSpec.icon) + .render.txt + if ( + iconSpec.color === undefined || + icon.startsWith("http:") || + icon.startsWith("https:") + ) { + return icon + } + const color = new TagRenderingConfig(iconSpec.color) + .render.txt + return icon + ":" + color + })).join(";") if (!icon) { icon = "./assets/svg/bug.svg" diff --git a/src/Logic/FeatureSource/Sources/FeatureSourceMerger.ts b/src/Logic/FeatureSource/Sources/FeatureSourceMerger.ts index 555d16d9b..b6eaa9b3f 100644 --- a/src/Logic/FeatureSource/Sources/FeatureSourceMerger.ts +++ b/src/Logic/FeatureSource/Sources/FeatureSourceMerger.ts @@ -1,8 +1,8 @@ import { Store, UIEventSource } from "../../UIEventSource" import { FeatureSource, IndexedFeatureSource, UpdatableFeatureSource } from "../FeatureSource" import { Feature } from "geojson" -import { Utils } from "../../../Utils" import { OsmFeature } from "../../../Models/OsmFeature" +import { Lists } from "../../../Utils/Lists" /** * The featureSourceMerger receives complete geometries from various sources. @@ -23,7 +23,7 @@ export default class FeatureSourceMerger>(new Map()) this.featuresById = this._featuresById - sources = Utils.NoNull(sources) + sources = Lists.noNull(sources) for (const source of sources) { source.features.addCallback(() => { this.addDataFromSources(sources) @@ -69,7 +69,7 @@ export default class FeatureSourceMerger = new Map() const unseen = new Set() diff --git a/src/Logic/FeatureSource/Sources/LastClickFeatureSource.ts b/src/Logic/FeatureSource/Sources/LastClickFeatureSource.ts index 46b4fbb56..cb02b9747 100644 --- a/src/Logic/FeatureSource/Sources/LastClickFeatureSource.ts +++ b/src/Logic/FeatureSource/Sources/LastClickFeatureSource.ts @@ -6,6 +6,7 @@ import BaseUIElement from "../../../UI/BaseUIElement" import { Utils } from "../../../Utils" import { OsmTags } from "../../../Models/OsmFeature" import { FeatureSource } from "../FeatureSource" +import { Lists } from "../../../Utils/Lists" /** * Highly specialized feature source. @@ -48,11 +49,9 @@ export class LastClickFeatureSource implements FeatureSource { allPresets.push(html) } - this.renderings = Utils.Dedup( - allPresets.map((uiElem) => - Utils.runningFromConsole ? "" : uiElem.ConstructElement().innerHTML - ) - ) + this.renderings = Lists.dedup(allPresets.map((uiElem) => + Utils.runningFromConsole ? "" : uiElem.ConstructElement().innerHTML + )) this._features = new UIEventSource([]) this.features = this._features diff --git a/src/Logic/FeatureSource/Sources/OsmFeatureSource.ts b/src/Logic/FeatureSource/Sources/OsmFeatureSource.ts index 568a10bff..ea08cb463 100644 --- a/src/Logic/FeatureSource/Sources/OsmFeatureSource.ts +++ b/src/Logic/FeatureSource/Sources/OsmFeatureSource.ts @@ -8,6 +8,7 @@ import { Feature } from "geojson" import FeatureSourceMerger from "../Sources/FeatureSourceMerger" import OsmObjectDownloader from "../../Osm/OsmObjectDownloader" import FullNodeDatabaseSource from "../TiledFeatureSource/FullNodeDatabaseSource" +import { Lists } from "../../../Utils/Lists" /** * If a tile is needed (requested via the UIEventSource in the constructor), will download the appropriate tile and pass it via 'handleTile' @@ -173,7 +174,7 @@ export default class OsmFeatureSource extends FeatureSourceMerger { for (let i = 0; i < features.length; i++) { features[i] = await this.patchIncompleteRelations(features[i], osmJson) } - features = Utils.NoNull(features) + features = Lists.noNull(features) features.forEach((f) => { f.properties["_backend"] = this._backend }) diff --git a/src/Logic/FeatureSource/Sources/OverpassFeatureSource.ts b/src/Logic/FeatureSource/Sources/OverpassFeatureSource.ts index f2443ff9d..80dafda5f 100644 --- a/src/Logic/FeatureSource/Sources/OverpassFeatureSource.ts +++ b/src/Logic/FeatureSource/Sources/OverpassFeatureSource.ts @@ -8,6 +8,7 @@ import { Utils } from "../../../Utils" import { TagsFilter } from "../../Tags/TagsFilter" import { BBox } from "../../BBox" import { OsmTags } from "../../../Models/OsmFeature" +import { Lists } from "../../../Utils/Lists" ("use strict") @@ -199,7 +200,7 @@ export default class OverpassFeatureSource implements UpdatableFeatureSource { */ private GetFilter(interpreterUrl: string, layersToDownload: LayerConfig[]): Overpass { let filters: TagsFilter[] = layersToDownload.map((layer) => layer.source.osmTags) - filters = Utils.NoNull(filters) + filters = Lists.noNull(filters) if (filters.length === 0) { return undefined } diff --git a/src/Logic/FeatureSource/TiledFeatureSource/LineSourceMerger.ts b/src/Logic/FeatureSource/TiledFeatureSource/LineSourceMerger.ts index 03e26ac3f..8290e70a3 100644 --- a/src/Logic/FeatureSource/TiledFeatureSource/LineSourceMerger.ts +++ b/src/Logic/FeatureSource/TiledFeatureSource/LineSourceMerger.ts @@ -5,6 +5,7 @@ import { Utils } from "../../../Utils" import { Feature, MultiLineString, Position } from "geojson" import { GeoOperations } from "../../GeoOperations" import { UpdatableDynamicTileSource } from "./DynamicTileSource" +import { Lists } from "../../../Utils/Lists" /** * The PolygonSourceMerger receives various small pieces of bigger polygons and stitches them together. @@ -32,7 +33,7 @@ export class LineSourceMerger extends UpdatableDynamicTileSource< } protected addDataFromSources(sources: FeatureSourceForTile[]) { - sources = Utils.NoNull(sources) + sources = Lists.noNull(sources) const all: Map> = new Map() const currentZoom = this._zoomlevel?.data ?? 0 for (const source of sources) { diff --git a/src/Logic/FeatureSource/TiledFeatureSource/PolygonSourceMerger.ts b/src/Logic/FeatureSource/TiledFeatureSource/PolygonSourceMerger.ts index 0c8e6a5ca..37bda203e 100644 --- a/src/Logic/FeatureSource/TiledFeatureSource/PolygonSourceMerger.ts +++ b/src/Logic/FeatureSource/TiledFeatureSource/PolygonSourceMerger.ts @@ -1,10 +1,10 @@ import { FeatureSourceForTile, UpdatableFeatureSource } from "../FeatureSource" import { Store } from "../../UIEventSource" import { BBox } from "../../BBox" -import { Utils } from "../../../Utils" import { Feature } from "geojson" import { GeoOperations } from "../../GeoOperations" import { UpdatableDynamicTileSource } from "./DynamicTileSource" +import { Lists } from "../../../Utils/Lists" /** * The PolygonSourceMerger receives various small pieces of bigger polygons and stitches them together. @@ -29,7 +29,7 @@ export class PolygonSourceMerger extends UpdatableDynamicTileSource< } protected addDataFromSources(sources: FeatureSourceForTile[]) { - sources = Utils.NoNull(sources) + sources = Lists.noNull(sources) const all: Map = new Map() const zooms: Map = new Map() diff --git a/src/Logic/GeoOperations.ts b/src/Logic/GeoOperations.ts index e23df3157..b99708b4b 100644 --- a/src/Logic/GeoOperations.ts +++ b/src/Logic/GeoOperations.ts @@ -14,6 +14,7 @@ import { } from "geojson" import { Tiles } from "../Models/TileRange" import { Utils } from "../Utils" +import { Lists } from "../Utils/Lists" ("use strict") @@ -597,7 +598,7 @@ export class GeoOperations { newFeatures.push(intersectionPart) } } - return Utils.NoNull(newFeatures) + return Lists.noNull(newFeatures) } public static toGpx( @@ -610,7 +611,7 @@ export class GeoOperations { if (title === undefined || title === "") { title = "Uploaded with MapComplete" } - title = Utils.EncodeXmlValue(title) + title = Utils.encodeXmlValue(title) const trackPoints: string[] = [] let locationsWithMeta: Feature[] if (Array.isArray(locations)) { @@ -664,7 +665,7 @@ export class GeoOperations { if (title === undefined || title === "") { title = "Created with MapComplete" } - title = Utils.EncodeXmlValue(title) + title = Utils.encodeXmlValue(title) const trackPoints: string[] = [] for (const l of locations) { let trkpt = ` ` diff --git a/src/Logic/ImageProviders/AllImageProviders.ts b/src/Logic/ImageProviders/AllImageProviders.ts index 69eb73dba..1be89dbd2 100644 --- a/src/Logic/ImageProviders/AllImageProviders.ts +++ b/src/Logic/ImageProviders/AllImageProviders.ts @@ -8,6 +8,7 @@ import { WikidataImageProvider } from "./WikidataImageProvider" import Panoramax from "./Panoramax" import { Utils } from "../../Utils" import { ServerSourceInfo } from "../../Models/SourceOverview" +import { Lists } from "../../Utils/Lists" /** * A generic 'from the interwebz' image picker, without attribution @@ -101,9 +102,7 @@ export default class AllImageProviders { Mapillary.singleton, AllImageProviders.genericImageProvider, ] - const allPrefixes = Utils.Dedup( - prefixes ?? [].concat(...sources.map((s) => s.defaultKeyPrefixes)) - ) + const allPrefixes = Lists.dedup(prefixes ?? [].concat(...sources.map((s) => s.defaultKeyPrefixes))) for (const prefix of allPrefixes) { for (const k in tags) { const v = tags[k] @@ -149,7 +148,7 @@ export default class AllImageProviders { allSources.push(singleSource) } const source = Stores.concat(allSources).map((result) => { - const all = Utils.concat(result) + const all = result.flatMap(x => x) return Utils.DedupOnId(all, (i) => [i?.id, i?.url, i?.alt_id]) }) this._cachedImageStores[cachekey] = source diff --git a/src/Logic/ImageProviders/ImageProvider.ts b/src/Logic/ImageProviders/ImageProvider.ts index 2e20642ba..8f67ef859 100644 --- a/src/Logic/ImageProviders/ImageProvider.ts +++ b/src/Logic/ImageProviders/ImageProvider.ts @@ -4,6 +4,7 @@ import { Utils } from "../../Utils" import { Feature, Point } from "geojson" import { ServerSourceInfo } from "../../Models/SourceOverview" import { ComponentType } from "svelte/types/runtime/internal/dev" +import { Lists } from "../../Utils/Lists" export interface ProvidedImage { url: string @@ -92,7 +93,7 @@ export default abstract class ImageProvider { ) { continue } - const values = Utils.NoEmpty(tags[key]?.split(";")?.map((v) => v.trim()) ?? []) + const values = Lists.noEmpty(tags[key]?.split(";")?.map((v) => v.trim()) ?? []) for (const value of values) { if (seenValues.has(value)) { continue diff --git a/src/Logic/ImageProviders/ImageUploadManager.ts b/src/Logic/ImageProviders/ImageUploadManager.ts index b9fc80293..88bad0bcc 100644 --- a/src/Logic/ImageProviders/ImageUploadManager.ts +++ b/src/Logic/ImageProviders/ImageUploadManager.ts @@ -15,6 +15,7 @@ import NoteCommentElement from "../../UI/Popup/Notes/NoteCommentElement" import OsmObjectDownloader from "../Osm/OsmObjectDownloader" import ExifReader from "exifreader" import { Utils } from "../../Utils" +import { Lists } from "../../Utils/Lists" /** * The ImageUploadManager has a @@ -176,7 +177,7 @@ export class ImageUploadManager { const failed: Set = new Set() this.uploadingAll = true do { - queue = Utils.NoNull(this._queue.imagesInQueue.data ?? []).filter( + queue = Lists.noNull(this._queue.imagesInQueue.data ?? []).filter( (item) => !failed.has(item) ) diff --git a/src/Logic/ImageProviders/Mapillary.ts b/src/Logic/ImageProviders/Mapillary.ts index 32c794098..128c8e2a9 100644 --- a/src/Logic/ImageProviders/Mapillary.ts +++ b/src/Logic/ImageProviders/Mapillary.ts @@ -7,6 +7,7 @@ import { Feature, Point } from "geojson" import { Store, UIEventSource } from "../UIEventSource" import { ServerSourceInfo } from "../../Models/SourceOverview" import { ComponentType } from "svelte/types/runtime/internal/dev" +import { Lists } from "../../Utils/Lists" export class Mapillary extends ImageProvider { public static readonly singleton = new Mapillary() @@ -74,11 +75,9 @@ export class Mapillary extends ImageProvider { pKey, } const baselink = `https://www.mapillary.com/app/?` - const paramsStr = Utils.NoNull( - Object.keys(params).map((k) => - params[k] === undefined ? undefined : k + "=" + params[k] - ) - ) + const paramsStr = Lists.noNull(Object.keys(params).map((k) => + params[k] === undefined ? undefined : k + "=" + params[k] + )) return baselink + paramsStr.join("&") } diff --git a/src/Logic/ImageProviders/WikidataImageProvider.ts b/src/Logic/ImageProviders/WikidataImageProvider.ts index 3a774652b..625a16872 100644 --- a/src/Logic/ImageProviders/WikidataImageProvider.ts +++ b/src/Logic/ImageProviders/WikidataImageProvider.ts @@ -6,6 +6,7 @@ import { Utils } from "../../Utils" import { Feature, Point } from "geojson" import { ServerSourceInfo } from "../../Models/SourceOverview" import { ComponentType } from "svelte/types/runtime/internal/dev" +import { Lists } from "../../Utils/Lists" export class WikidataImageProvider extends ImageProvider { public static readonly singleton = new WikidataImageProvider() @@ -13,7 +14,7 @@ export class WikidataImageProvider extends ImageProvider { public readonly name = "Wikidata" private static readonly keyBlacklist: ReadonlySet = new Set([ "mapillary", - ...Utils.Times((i) => "mapillary:" + i, 10), + ...Utils.times((i) => "mapillary:" + i, 10), ]) private constructor() { @@ -60,7 +61,7 @@ export class WikidataImageProvider extends ImageProvider { const promises = WikimediaImageProvider.singleton.ExtractUrls(undefined, commons) allImages.push(promises) } - const resolved = await Promise.all(Utils.NoNull(allImages)) + const resolved = await Promise.all(Lists.noNull(allImages)) const flattened = resolved.flatMap((x) => x) if (flattened.length === 1) { flattened[0].originalAttribute = { key, value } diff --git a/src/Logic/Osm/Actions/DeleteAction.ts b/src/Logic/Osm/Actions/DeleteAction.ts index 128b9acee..922ef5d3a 100644 --- a/src/Logic/Osm/Actions/DeleteAction.ts +++ b/src/Logic/Osm/Actions/DeleteAction.ts @@ -7,8 +7,8 @@ import { TagsFilter } from "../../Tags/TagsFilter" import { And } from "../../Tags/And" import { Tag } from "../../Tags/Tag" import { OsmId } from "../../../Models/OsmFeature" -import { Utils } from "../../../Utils" import OsmObjectDownloader from "../OsmObjectDownloader" +import { Lists } from "../../../Utils/Lists" export default class DeleteAction extends OsmChangeAction { private readonly _softDeletionTags: TagsFilter @@ -50,12 +50,12 @@ export default class DeleteAction extends OsmChangeAction { this._softDeletionTags = softDeletionTags } else { this._softDeletionTags = new And( - Utils.NoNull([ - softDeletionTags, - new Tag( - "fixme", - `A mapcomplete user marked this feature to be deleted (${meta.specialMotivation})` - ), + Lists.noNull([ + softDeletionTags, + new Tag( + "fixme", + `A mapcomplete user marked this feature to be deleted (${meta.specialMotivation})` + ), ]) ) } diff --git a/src/Logic/Osm/Actions/ReplaceGeometryAction.ts b/src/Logic/Osm/Actions/ReplaceGeometryAction.ts index 41f7e8567..9fb99e889 100644 --- a/src/Logic/Osm/Actions/ReplaceGeometryAction.ts +++ b/src/Logic/Osm/Actions/ReplaceGeometryAction.ts @@ -13,6 +13,7 @@ import { Utils } from "../../../Utils" import { OsmConnection } from "../OsmConnection" import { Feature, Geometry, LineString, Point } from "geojson" import FullNodeDatabaseSource from "../../FeatureSource/TiledFeatureSource/FullNodeDatabaseSource" +import { Lists } from "../../../Utils/Lists" export default class ReplaceGeometryAction extends OsmChangeAction implements PreviewableAction { /** @@ -164,7 +165,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr preview.push(feature) }) - return StaticFeatureSource.fromGeojson(Utils.NoNull(preview)) + return StaticFeatureSource.fromGeojson(Lists.noNull(preview)) } /** @@ -317,7 +318,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr candidate = undefined moveDistance = Infinity distances.forEach((distances, nodeId) => { - const minDist = Math.min(...Utils.NoNull(distances)) + const minDist = Math.min(...(Lists.noNull(distances))) if (moveDistance > minDist) { // We have found a candidate to move candidate = nodeId diff --git a/src/Logic/Osm/Changes.ts b/src/Logic/Osm/Changes.ts index 541192c9c..14dae7e0c 100644 --- a/src/Logic/Osm/Changes.ts +++ b/src/Logic/Osm/Changes.ts @@ -18,6 +18,7 @@ import DeleteAction from "./Actions/DeleteAction" import MarkdownUtils from "../../Utils/MarkdownUtils" import FeaturePropertiesStore from "../FeatureSource/Actors/FeaturePropertiesStore" import { Feature, Point } from "geojson" +import { Lists } from "../../Utils/Lists" /** * Handles all changes made to OSM. @@ -260,7 +261,7 @@ export class Changes { } public static GetNeededIds(changes: ChangeDescription[]) { - return Utils.Dedup(changes.filter((c) => c.id >= 0).map((c) => c.type + "/" + c.id)) + return Lists.dedup(changes.filter((c) => c.id >= 0).map((c) => c.type + "/" + c.id)) } /** @@ -467,8 +468,8 @@ export class Changes { if (change.changes !== undefined) { switch (change.type) { case "node": { - const nlat = Utils.Round7(change.changes.lat) - const nlon = Utils.Round7(change.changes.lon) + const nlat = Utils.round7(change.changes.lat) + const nlon = Utils.round7(change.changes.lon) const n = obj if (n.lat !== nlat || n.lon !== nlon) { n.lat = nlat @@ -717,11 +718,9 @@ export class Changes { * We _do not_ pass in the Changes object itself - we want the data from OSM directly in order to apply the changes */ const downloader = new OsmObjectDownloader(this.backend, undefined) - const osmObjects = Utils.NoNull( - await Promise.all<{ id: string; osmObj: OsmObject | "deleted" }>( - neededIds.map((id) => this.getOsmObject(id, downloader)) - ) - ) + const osmObjects = Lists.noNull(await Promise.all<{ id: string; osmObj: OsmObject | "deleted" }>( + neededIds.map((id) => this.getOsmObject(id, downloader)) + )) // Drop changes to deleted items for (const { osmObj, id } of osmObjects) { @@ -801,7 +800,7 @@ export class Changes { value: descr.meta.specialMotivation, })) - const distances = Utils.NoNull(pending.map((descr) => descr.meta.distanceToObject)) + const distances = Lists.noNull(pending.map((descr) => descr.meta.distanceToObject)) distances.sort((a, b) => a - b) const perBinCount = Constants.distanceToChangeObjectBins.map(() => 0) @@ -816,23 +815,21 @@ export class Changes { } } - const perBinMessage = Utils.NoNull( - perBinCount.map((count, i) => { - if (count === 0) { - return undefined - } - const maxD = maxDistances[i] - let key = `change_within_${maxD}m` - if (maxD === Number.MAX_VALUE) { - key = `change_over_${maxDistances[i - 1]}m` - } - return { - key, - value: count, - aggregate: true, - } - }) - ) + const perBinMessage = Lists.noNull(perBinCount.map((count, i) => { + if (count === 0) { + return undefined + } + const maxD = maxDistances[i] + let key = `change_within_${maxD}m` + if (maxD === Number.MAX_VALUE) { + key = `change_over_${maxDistances[i - 1]}m` + } + return { + key, + value: count, + aggregate: true, + } + })) // This method is only called with changedescriptions for this theme const theme = pending[0].meta.theme diff --git a/src/Logic/Osm/ChangesetHandler.ts b/src/Logic/Osm/ChangesetHandler.ts index 060acfc47..b085119f5 100644 --- a/src/Logic/Osm/ChangesetHandler.ts +++ b/src/Logic/Osm/ChangesetHandler.ts @@ -8,6 +8,7 @@ import { Utils } from "../../Utils" import FeaturePropertiesStore from "../FeatureSource/Actors/FeaturePropertiesStore" import { AndroidPolyfill } from "../Web/AndroidPolyfill" import ImageUploadQueue from "../ImageProviders/ImageUploadQueue" +import { Lists } from "../../Utils/Lists" export interface ChangesetTag { key: string @@ -393,7 +394,7 @@ export class ChangesetHandler { private async UpdateTags(csId: number, tags: ChangesetTag[]) { tags = ChangesetHandler.removeDuplicateMetaTags(tags) - tags = Utils.NoNull(tags).filter( + tags = Lists.noNull(tags).filter( (tag) => tag.key !== undefined && tag.value !== undefined && diff --git a/src/Logic/Osm/OsmObject.ts b/src/Logic/Osm/OsmObject.ts index c74f59fc8..b85bc55b8 100644 --- a/src/Logic/Osm/OsmObject.ts +++ b/src/Logic/Osm/OsmObject.ts @@ -150,7 +150,7 @@ export abstract class OsmObject { } const v = this.tags[key] if (v !== "" && v !== undefined) { - tags += ` ` diff --git a/src/Logic/Osm/OsmPreferences.ts b/src/Logic/Osm/OsmPreferences.ts index dcc1eac1a..db8dcfa27 100644 --- a/src/Logic/Osm/OsmPreferences.ts +++ b/src/Logic/Osm/OsmPreferences.ts @@ -2,6 +2,7 @@ import { Store, UIEventSource } from "../UIEventSource" import { OsmConnection } from "./OsmConnection" import { LocalStorageSource } from "../Web/LocalStorageSource" import { Utils } from "../../Utils" +import { Lists } from "../../Utils/Lists" import OSMAuthInstance = OSMAuth.osmAuth export class OsmPreferences { @@ -270,7 +271,7 @@ export class OsmPreferences { return } // _All_ keys are deleted first, to avoid pending parts - const keysToDelete = Utils.Dedup(OsmPreferences.keysStartingWith(this.seenKeys, k)) + const keysToDelete = Lists.dedup(OsmPreferences.keysStartingWith(this.seenKeys, k)) if (v === null || v === undefined || v === "" || v === "undefined" || v === "null") { for (const k of keysToDelete) { await this.deleteKeyDirectly(k) diff --git a/src/Logic/Search/CombinedSearcher.ts b/src/Logic/Search/CombinedSearcher.ts index 261826c7d..cafa3e5f7 100644 --- a/src/Logic/Search/CombinedSearcher.ts +++ b/src/Logic/Search/CombinedSearcher.ts @@ -13,7 +13,7 @@ export default class CombinedSearcher implements GeocodingProvider { * @param providers */ constructor(...providers: ReadonlyArray) { - this._providers = Utils.NoNull(providers) + this._providers = Utils.noNull(providers) this._providersWithSuggest = this._providers.filter((pr) => pr.suggest !== undefined) } diff --git a/src/Logic/Search/CoordinateSearch.ts b/src/Logic/Search/CoordinateSearch.ts index de74239c1..cc0727e9c 100644 --- a/src/Logic/Search/CoordinateSearch.ts +++ b/src/Logic/Search/CoordinateSearch.ts @@ -1,7 +1,7 @@ import GeocodingProvider, { GeocodeResult } from "./GeocodingProvider" -import { Utils } from "../../Utils" import { ImmutableStore, Store } from "../UIEventSource" import CoordinateParser from "coordinate-parser" +import { Lists } from "../../Utils/Lists" /** * A simple search-class which interprets possible locations @@ -71,13 +71,11 @@ export default class CoordinateSearch implements GeocodingProvider { * results[0] // => {lat: 51.047977, lon: 3.51184, "display_name": "lon: 3.51184, lat: 51.047977", "category": "coordinate","osm_id": "3.51184/51.047977", "source": "coordinate:latlon"} */ private directSearch(query: string): GeocodeResult[] { - const matches = Utils.NoNull(CoordinateSearch.latLonRegexes.map((r) => query.match(r))).map( + const matches = Lists.noNull(CoordinateSearch.latLonRegexes.map((r) => query.match(r))).map( (m) => CoordinateSearch.asResult(m[2], m[1], "latlon") ) - const matchesLonLat = Utils.NoNull( - CoordinateSearch.lonLatRegexes.map((r) => query.match(r)) - ).map((m) => CoordinateSearch.asResult(m[1], m[2], "lonlat")) + const matchesLonLat = Lists.noNull(CoordinateSearch.lonLatRegexes.map((r) => query.match(r))).map((m) => CoordinateSearch.asResult(m[1], m[2], "lonlat")) const init = matches.concat(matchesLonLat) if (init.length > 0) { return init diff --git a/src/Logic/Search/FilterSearch.ts b/src/Logic/Search/FilterSearch.ts index bf4b32d45..251a53e93 100644 --- a/src/Logic/Search/FilterSearch.ts +++ b/src/Logic/Search/FilterSearch.ts @@ -4,6 +4,7 @@ import FilterConfig, { FilterConfigOption } from "../../Models/ThemeConfig/Filte import LayerConfig from "../../Models/ThemeConfig/LayerConfig" import LayerState from "../State/LayerState" import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig" +import { Lists } from "../../Utils/Lists" export type FilterSearchResult = { option: FilterConfigOption @@ -64,7 +65,7 @@ export default class FilterSearch { ].flatMap((term) => [term, ...(term?.split(" ") ?? [])]) terms = terms.map((t) => Utils.simplifyStringForSearch(t)) terms.push(option.emoji) - Utils.NoNullInplace(terms) + Lists.noNullInplace(terms) const distances = queries.flatMap((query) => terms.map((entry) => { const d = Utils.levenshteinDistance(query, entry.slice(0, query.length)) diff --git a/src/Logic/Search/LocalElementSearch.ts b/src/Logic/Search/LocalElementSearch.ts index b96741eef..93aead07b 100644 --- a/src/Logic/Search/LocalElementSearch.ts +++ b/src/Logic/Search/LocalElementSearch.ts @@ -5,6 +5,7 @@ import { Feature } from "geojson" import { GeoOperations } from "../GeoOperations" import { ImmutableStore, Store, Stores } from "../UIEventSource" import OpenStreetMapIdSearch from "./OpenStreetMapIdSearch" +import { Lists } from "../../Utils/Lists" type IntermediateResult = { feature: Feature @@ -41,13 +42,13 @@ export default class LocalElementSearch implements GeocodingProvider { for (const feature of features) { const props = feature.properties - const searchTerms: string[] = Utils.NoNull([ - props.name, - props.alt_name, - props.local_name, - props["addr:street"] && props["addr:number"] - ? props["addr:street"] + props["addr:number"] - : undefined, + const searchTerms: string[] = Lists.noNull([ + props.name, + props.alt_name, + props.local_name, + props["addr:street"] && props["addr:number"] + ? props["addr:street"] + props["addr:number"] + : undefined, ]) let levehnsteinD: number diff --git a/src/Logic/Search/OpenStreetMapIdSearch.ts b/src/Logic/Search/OpenStreetMapIdSearch.ts index eea015f34..92642b401 100644 --- a/src/Logic/Search/OpenStreetMapIdSearch.ts +++ b/src/Logic/Search/OpenStreetMapIdSearch.ts @@ -1,8 +1,8 @@ import { Store, UIEventSource } from "../UIEventSource" import GeocodingProvider, { GeocodeResult, GeocodingOptions } from "./GeocodingProvider" import { OsmId } from "../../Models/OsmFeature" -import { Utils } from "../../Utils" import OsmObjectDownloader from "../Osm/OsmObjectDownloader" +import { Lists } from "../../Utils/Lists" export default class OpenStreetMapIdSearch implements GeocodingProvider { private static readonly regex = @@ -76,7 +76,7 @@ export default class OpenStreetMapIdSearch implements GeocodingProvider { async search(query: string, _: GeocodingOptions): Promise { if (!isNaN(Number(query))) { const n = Number(query) - return Utils.NoNullInplace( + return Lists.noNullInplace( await Promise.all([ this.getInfoAbout(`node/${n}`).catch(() => undefined), this.getInfoAbout(`way/${n}`).catch(() => undefined), diff --git a/src/Logic/Search/SearchUtils.ts b/src/Logic/Search/SearchUtils.ts index 520341faf..a50ac5bf7 100644 --- a/src/Logic/Search/SearchUtils.ts +++ b/src/Logic/Search/SearchUtils.ts @@ -1,6 +1,7 @@ import Locale from "../../UI/i18n/Locale" import { Utils } from "../../Utils" import ThemeSearch from "./ThemeSearch" +import { Lists } from "../../Utils/Lists" export default class SearchUtils { /** Applies special search terms, such as 'studio', 'osmcha', ... @@ -66,7 +67,7 @@ export default class SearchUtils { } else { terms = (keywords[language] ?? []).concat(keywords["*"]) } - const termsAll = Utils.NoNullInplace(terms).flatMap((t) => t.split(" ")) + const termsAll = Lists.noNullInplace(terms).flatMap((t) => t.split(" ")) let distanceSummed = 0 for (let i = 0; i < queryParts.length; i++) { diff --git a/src/Logic/Search/ThemeSearch.ts b/src/Logic/Search/ThemeSearch.ts index d136713a8..96530d93d 100644 --- a/src/Logic/Search/ThemeSearch.ts +++ b/src/Logic/Search/ThemeSearch.ts @@ -8,6 +8,7 @@ import Fuse, { IFuseOptions } from "fuse.js" import Constants from "../../Models/Constants" import Locale from "../../UI/i18n/Locale" import { Utils } from "../../Utils" +import { Lists } from "../../Utils/Lists" export class ThemeSearchIndex { private readonly themeIndex: Fuse @@ -18,7 +19,7 @@ export class ThemeSearchIndex { themesToSearch?: MinimalThemeInformation[], layersToIgnore: string[] = [] ) { - const themes = Utils.NoNull(themesToSearch ?? ThemeSearch.officialThemes?.themes) + const themes = Utils.noNull(themesToSearch ?? ThemeSearch.officialThemes?.themes) if (!themes) { throw "No themes loaded. Did generate:layeroverview fail?" } @@ -100,7 +101,7 @@ export class ThemeSearchIndex { const knownHidden: Store = Stores.listStabilized( UserRelatedState.initDiscoveredHiddenThemes(state.osmConnection) .stabilized(1000) - .map((list) => Utils.Dedup(list)) + .map((list) => Lists.dedup(list)) ) const otherThemes: MinimalThemeInformation[] = ThemeSearch.officialThemes.themes.filter( (th) => th.id !== state.theme.id diff --git a/src/Logic/State/SearchState.ts b/src/Logic/State/SearchState.ts index 31b75a7b3..339970849 100644 --- a/src/Logic/State/SearchState.ts +++ b/src/Logic/State/SearchState.ts @@ -18,8 +18,8 @@ import { Feature } from "geojson" import OpenLocationCodeSearch from "../Search/OpenLocationCodeSearch" import { BBox } from "../BBox" import { QueryParameters } from "../Web/QueryParameters" -import { Utils } from "../../Utils" import { NominatimGeocoding } from "../Search/NominatimGeocoding" +import { Lists } from "../../Utils/Lists" export default class SearchState { public readonly feedback: UIEventSource = new UIEventSource(undefined) @@ -83,7 +83,7 @@ export default class SearchState { } }))) this.runningEngines = isRunningPerEngine.bindD( - listOfSources => Stores.concat(listOfSources).mapD(list => Utils.NoNull(list))) + listOfSources => Stores.concat(listOfSources).mapD(list => Lists.noNull(list))) this.failedEngines = suggestionsListWithSource @@ -102,7 +102,7 @@ export default class SearchState { return [] } }), - ))).map(list => Utils.NoNull(list?.flatMap(x => x) ?? [])) + ))).map(list => Lists.noNull(list?.flatMap(x => x) ?? [])) this.suggestionsSearchRunning = this.runningEngines.map(running => running?.length > 0) this.suggestions = suggestionsList.bindD((suggestions) => diff --git a/src/Logic/State/UserRelatedState.ts b/src/Logic/State/UserRelatedState.ts index 3aecc7de0..abb8df6f2 100644 --- a/src/Logic/State/UserRelatedState.ts +++ b/src/Logic/State/UserRelatedState.ts @@ -20,6 +20,7 @@ import Showdown from "showdown" import { LocalStorageSource } from "../Web/LocalStorageSource" import { GeocodeResult } from "../Search/GeocodingProvider" import Translations from "../../UI/i18n/Translations" +import { Lists } from "../../Utils/Lists" class RoundRobinStore { private readonly _store: UIEventSource @@ -41,7 +42,7 @@ class RoundRobinStore { private set() { const v = this._store.data const i = this._index.data - const newList = Utils.NoNull(v.slice(i + 1, v.length).concat(v.slice(0, i + 1))) + const newList = Lists.noNull(v.slice(i + 1, v.length).concat(v.slice(0, i + 1))) if (newList.length === 0) { this._index.set(0) } @@ -89,7 +90,7 @@ export class OptionallySyncedHistory { defaultValue: "sync", }) - this.syncedBackingStore = UIEventSource.concat(Utils.TimesT(maxHistory, (i) => { + this.syncedBackingStore = UIEventSource.concat(Utils.timesT(maxHistory, (i) => { const pref = osmconnection.getPreference(key + "-hist-" + i + "-") return UIEventSource.asObject(pref, undefined) })) @@ -555,27 +556,25 @@ export default class UserRelatedState { const untranslated = missing.untranslated.get(language) ?? [] const hasMissingTheme = untranslated.some((k) => k.startsWith("themes:")) - const missingLayers = Utils.Dedup( - untranslated - .filter((k) => k.startsWith("layers:")) - .map((k) => k.slice("layers:".length).split(".")[0]) - ) + const missingLayers = Lists.dedup(untranslated + .filter((k) => k.startsWith("layers:")) + .map((k) => k.slice("layers:".length).split(".")[0])) - const zenLinks: { link: string; id: string }[] = Utils.NoNull([ - hasMissingTheme - ? { - id: "theme:" + layout.id, - link: Translations.hrefToWeblateZen( - language, - "themes", - layout.id - ), - } - : undefined, - ...missingLayers.map((id) => ({ - id: "layer:" + id, - link: Translations.hrefToWeblateZen(language, "layers", id), - })), + const zenLinks: { link: string; id: string }[] = Lists.noNull([ + hasMissingTheme + ? { + id: "theme:" + layout.id, + link: Translations.hrefToWeblateZen( + language, + "themes", + layout.id + ), + } + : undefined, + ...missingLayers.map((id) => ({ + id: "layer:" + id, + link: Translations.hrefToWeblateZen(language, "layers", id), + })), ]) const untranslated_count = untranslated.length amendedPrefs.data["_translation_total"] = "" + total diff --git a/src/Logic/Tags/TagUtils.ts b/src/Logic/Tags/TagUtils.ts index 36783efb1..e2a4572e3 100644 --- a/src/Logic/Tags/TagUtils.ts +++ b/src/Logic/Tags/TagUtils.ts @@ -11,6 +11,7 @@ import key_counts from "../../assets/key_totals.json" import { ConversionContext } from "../../Models/ThemeConfig/Conversion/ConversionContext" import { FlatTag, TagsFilterClosed, UploadableTag } from "./TagTypes" +import { Lists } from "../../Utils/Lists" type Tags = Record @@ -383,7 +384,7 @@ export class TagUtils { const keyValues = TagUtils.SplitKeys(tagsFilters) const and: UploadableTag[] = [] for (const key in keyValues) { - const values = Utils.Dedup(keyValues[key]).filter((v) => v !== "") + const values = Lists.dedup(keyValues[key]).filter((v) => v !== "") values.sort() and.push(new Tag(key, values.join(";"))) } @@ -742,7 +743,7 @@ export class TagUtils { if (level === undefined || level === null) { return [] } - let spec = Utils.NoNull([level]) + let spec = Lists.noNull([level]) spec = [].concat(...spec.map((s) => s?.split(";"))) spec = [].concat( ...spec.map((s) => { @@ -764,7 +765,7 @@ export class TagUtils { return values }) ) - return Utils.NoNull(spec) + return Lists.noNull(spec) } private static ParseTagUnsafe(json: TagConfigJson, context: string = ""): TagsFilterClosed { @@ -919,10 +920,10 @@ export class TagUtils { public static GetPopularity(tag: TagsFilter): number | undefined { if (tag instanceof And) { - return Math.min(...Utils.NoNull(tag.and.map((t) => TagUtils.GetPopularity(t)))) - 1 + return Math.min(...(Lists.noNull(tag.and.map((t) => TagUtils.GetPopularity(t))))) - 1 } if (tag instanceof Or) { - return Math.max(...Utils.NoNull(tag.or.map((t) => TagUtils.GetPopularity(t)))) + 1 + return Math.max(...(Lists.noNull(tag.or.map((t) => TagUtils.GetPopularity(t))))) + 1 } if (tag instanceof Tag) { return TagUtils.GetCount(tag.key, tag.value) diff --git a/src/Logic/Web/NameSuggestionIndex.ts b/src/Logic/Web/NameSuggestionIndex.ts index 18ffe33d6..6fdbbc1cf 100644 --- a/src/Logic/Web/NameSuggestionIndex.ts +++ b/src/Logic/Web/NameSuggestionIndex.ts @@ -9,6 +9,7 @@ import { RegexTag } from "../Tags/RegexTag" import { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson" import { TagUtils } from "../Tags/TagUtils" import Constants from "../../Models/Constants" +import { Lists } from "../../Utils/Lists" /** * Main name suggestion index file @@ -103,7 +104,7 @@ export default class NameSuggestionIndex { } }) ) - stats = Utils.NoNull(stats) + stats = Lists.noNull(stats) if (stats.length === 1) { return stats[0] } @@ -282,7 +283,7 @@ export default class NameSuggestionIndex { } const keys = Object.keys(this.nsiFile.nsi) const all = keys.map((k) => this.nsiFile.nsi[k].properties.path.split("/")[0]) - this._supportedTypes = Utils.Dedup(all).map((s) => { + this._supportedTypes = Lists.dedup(all).map((s) => { if (s.endsWith("s")) { s = s.substring(0, s.length - 1) } diff --git a/src/Logic/Web/Wikidata.ts b/src/Logic/Web/Wikidata.ts index 847ea6dac..133b22ee5 100644 --- a/src/Logic/Web/Wikidata.ts +++ b/src/Logic/Web/Wikidata.ts @@ -2,6 +2,7 @@ import { Utils } from "../../Utils" import { Store, UIEventSource } from "../UIEventSource" import { SimplifiedClaims, WBK } from "wikibase-sdk" import { ServerSourceInfo } from "../../Models/SourceOverview" +import { Lists } from "../../Utils/Lists" export class WikidataResponse { public readonly id: string @@ -294,7 +295,7 @@ export default class Wikidata { } }) ) - return Utils.NoNull(maybeResponses.map((r) => r["success"])) + return Lists.noNull(maybeResponses.map((r) => r["success"])) } /** diff --git a/src/Models/FilteredLayer.ts b/src/Models/FilteredLayer.ts index c5ec5005a..94b01adf6 100644 --- a/src/Models/FilteredLayer.ts +++ b/src/Models/FilteredLayer.ts @@ -9,6 +9,7 @@ import { Utils } from "../Utils" import { TagUtils } from "../Logic/Tags/TagUtils" import { And } from "../Logic/Tags/And" import { GlobalFilter } from "./GlobalFilter" +import { Lists } from "../Utils/Lists" export default class FilteredLayer { /** @@ -287,7 +288,7 @@ export default class FilteredLayer { } needed.push(filter.options[state.data].osmTags) } - needed = Utils.NoNull(needed) + needed = Lists.noNull(needed) if (needed.length == 0) { return undefined } diff --git a/src/Models/SourceOverview.ts b/src/Models/SourceOverview.ts index db7ff3613..15e5d1b41 100644 --- a/src/Models/SourceOverview.ts +++ b/src/Models/SourceOverview.ts @@ -11,9 +11,10 @@ import { ThemeConfigJson } from "../../src/Models/ThemeConfig/Json/ThemeConfigJs import SpecialVisualizations from "../../src/UI/SpecialVisualizations" import ValidationUtils from "../../src/Models/ThemeConfig/Conversion/ValidationUtils" import { - QuestionableTagRenderingConfigJson + QuestionableTagRenderingConfigJson, } from "../../src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson" import { LayerConfigJson } from "../../src/Models/ThemeConfig/Json/LayerConfigJson" +import { Lists } from "../Utils/Lists" export interface ServerSourceInfo { url: string @@ -81,7 +82,7 @@ export class SourceOverview { const geojsonSources: string[] = layout?.layers?.map((l) => l.source?.geojsonSource) ?? [] - return Utils.NoNull(apiUrls.concat(...geojsonSources)).filter((item) => { + return Lists.noNull(apiUrls.concat(...geojsonSources)).filter((item) => { if (typeof item === "string") { return true } @@ -117,7 +118,7 @@ export class SourceOverview { "Background layer source or supporting sources for " + f.properties.id, trigger: ["specific_feature"], category: "maplayer", - moreInfo: Utils.NoEmpty([ + moreInfo: Lists.noEmpty([ "https://github.com/osmlab/editor-layer-index", f.properties?.attribution?.url, ]), diff --git a/src/Models/ThemeConfig/Conversion/AddPrefixToTagRenderingConfig.ts b/src/Models/ThemeConfig/Conversion/AddPrefixToTagRenderingConfig.ts index ab93d767e..88fff1b2a 100644 --- a/src/Models/ThemeConfig/Conversion/AddPrefixToTagRenderingConfig.ts +++ b/src/Models/ThemeConfig/Conversion/AddPrefixToTagRenderingConfig.ts @@ -7,6 +7,7 @@ import { QuestionableTagRenderingConfigJson, } from "../Json/QuestionableTagRenderingConfigJson" import { Utils } from "../../../Utils" +import { ConversionContext } from "./ConversionContext" export default class AddPrefixToTagRenderingConfig extends DesugaringStep { private readonly _prefix: string @@ -142,7 +143,8 @@ export default class AddPrefixToTagRenderingConfig extends DesugaringStep + json: Readonly, + context: ConversionContext ): QuestionableTagRenderingConfigJson { let freeform = json.freeform if (freeform) { diff --git a/src/Models/ThemeConfig/Conversion/Conversion.ts b/src/Models/ThemeConfig/Conversion/Conversion.ts index 43baaf5ba..c0a10a102 100644 --- a/src/Models/ThemeConfig/Conversion/Conversion.ts +++ b/src/Models/ThemeConfig/Conversion/Conversion.ts @@ -1,7 +1,7 @@ import { LayerConfigJson } from "../Json/LayerConfigJson" -import { Utils } from "../../../Utils" import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson" import { ConversionContext } from "./ConversionContext" +import { Lists } from "../../../Utils/Lists" export interface DesugaringContext { tagRenderings: Map @@ -219,7 +219,7 @@ export class Concat extends Conversion { return values } const vals: T[][] = new Each(this._step).convert(values, context.inOperation("concat")) - return [].concat(...vals) + return vals.flatMap(l => l) } } @@ -264,7 +264,6 @@ export class Cached extends Conversion { } export class Fuse extends DesugaringStep { - protected debug = false private readonly steps: DesugaringStep[] constructor(doc: string, ...steps: DesugaringStep[]) { @@ -274,18 +273,12 @@ export class Fuse extends DesugaringStep { "This fused pipeline of the following steps: " + steps.map((s) => s.name).join(", ") ) - this.steps = Utils.NoNull(steps) + this.steps = Lists.noNull(steps) } - public enableDebugging(): Fuse { - this.debug = true - return this - } convert(json: T, context: ConversionContext): T { - const timings = [] for (let i = 0; i < this.steps.length; i++) { - const start = new Date() const step = this.steps[i] try { const r = step.convert(json, context.inOperation(step.name)) @@ -297,14 +290,6 @@ export class Fuse extends DesugaringStep { console.error("Step " + step.name + " failed due to ", e, e.stack) throw e } - if (this.debug) { - const stop = new Date() - const timeNeededMs = stop.getTime() - start.getTime() - timings.push(timeNeededMs) - } - } - if (this.debug) { - console.log("Time needed,", timings.join(", ")) } return json } diff --git a/src/Models/ThemeConfig/Conversion/DetectMappingsWithImages.ts b/src/Models/ThemeConfig/Conversion/DetectMappingsWithImages.ts index bdd525073..9bff68f79 100644 --- a/src/Models/ThemeConfig/Conversion/DetectMappingsWithImages.ts +++ b/src/Models/ThemeConfig/Conversion/DetectMappingsWithImages.ts @@ -1,9 +1,9 @@ import { DesugaringStep } from "./Conversion" import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson" import { ConversionContext } from "./ConversionContext" -import { Utils } from "../../../Utils" import Translations from "../../../UI/i18n/Translations" import { DoesImageExist } from "./Validation" +import { Lists } from "../../../Utils/Lists" export class DetectMappingsWithImages extends DesugaringStep { private readonly _doesImageExist: DoesImageExist @@ -45,7 +45,7 @@ export class DetectMappingsWithImages extends DesugaringStep= 0 - const images = Utils.Dedup(Translations.T(mapping.then)?.ExtractImages() ?? []) + const images = Lists.dedup(Translations.T(mapping.then)?.ExtractImages() ?? []) const ctx = context.enters("mappings", i) if (images.length > 0) { if (!ignore) { diff --git a/src/Models/ThemeConfig/Conversion/ExpandFilter.ts b/src/Models/ThemeConfig/Conversion/ExpandFilter.ts index 3454ce382..b4e742362 100644 --- a/src/Models/ThemeConfig/Conversion/ExpandFilter.ts +++ b/src/Models/ThemeConfig/Conversion/ExpandFilter.ts @@ -14,6 +14,7 @@ import Translations from "../../../UI/i18n/Translations" import { FlatTag, OptimizedTag, TagsFilterClosed } from "../../../Logic/Tags/TagTypes" import { TagsFilter } from "../../../Logic/Tags/TagsFilter" import { Translation } from "../../../UI/i18n/Translation" +import { Lists } from "../../../Utils/Lists" export class PruneFilters extends DesugaringStep { constructor() { @@ -107,9 +108,7 @@ export class PruneFilters extends DesugaringStep { const sourceTags = TagUtils.Tag(json.source["osmTags"]) return { ...json, - filter: Utils.NoNull( - json.filter?.map((obj) => this.prune(sourceTags, obj, context)) - ), + filter: Lists.noNull(json.filter?.map((obj) => this.prune(sourceTags, obj, context))), } } } diff --git a/src/Models/ThemeConfig/Conversion/ExpandTagRendering.ts b/src/Models/ThemeConfig/Conversion/ExpandTagRendering.ts index 3af5888c2..28cbd243c 100644 --- a/src/Models/ThemeConfig/Conversion/ExpandTagRendering.ts +++ b/src/Models/ThemeConfig/Conversion/ExpandTagRendering.ts @@ -8,6 +8,7 @@ import { Utils } from "../../../Utils" import { AddContextToTranslations } from "./AddContextToTranslations" import AddPrefixToTagRenderingConfig from "./AddPrefixToTagRenderingConfig" import { Translatable } from "../Json/Translatable" +import { Lists } from "../../../Utils/Lists" export class ExpandTagRendering extends Conversion< | string @@ -41,8 +42,7 @@ export class ExpandTagRendering extends Conversion< ) { super( "ExpandTagRendering", - "Converts a tagRenderingSpec into the full tagRendering, e.g. by substituting the tagRendering by the shared-question and reusing the builtins", - [] + "Converts a tagRenderingSpec into the full tagRendering, e.g. by substituting the tagRendering by the shared-question and reusing the builtins" ) this._state = state this._self = self @@ -387,7 +387,7 @@ export class ExpandTagRendering extends Conversion< if (layer === undefined) { const candidates = Utils.sortedByLevenshteinDistance( layerName, - Utils.NoNull(Array.from(state.sharedLayers.keys())) + Lists.noNull(Array.from(state.sharedLayers.keys())) ) if (candidates.length === 0) { ctx.err( @@ -413,7 +413,7 @@ export class ExpandTagRendering extends Conversion< // We are dealing with a looping import, no error is necessary continue } - candidates = Utils.NoNull(layer.tagRenderings.map((tr) => tr["id"])).map( + candidates = Lists.noNull(layer.tagRenderings.map((tr) => tr["id"])).map( (id) => layerName + "." + id ) } diff --git a/src/Models/ThemeConfig/Conversion/FixImages.ts b/src/Models/ThemeConfig/Conversion/FixImages.ts index 2902e6afc..a759d9748 100644 --- a/src/Models/ThemeConfig/Conversion/FixImages.ts +++ b/src/Models/ThemeConfig/Conversion/FixImages.ts @@ -7,6 +7,7 @@ import Translations from "../../../UI/i18n/Translations" import { parse as parse_html } from "node-html-parser" import { ConversionContext } from "./ConversionContext" +import { Lists } from "../../../Utils/Lists" export class ExtractImages extends Conversion< ThemeConfigJson, @@ -243,16 +244,12 @@ export class ExtractImages extends Conversion< } // Split "circle:white;./assets/layers/.../something.svg" into ["circle", "./assets/layers/.../something.svg"] - const allPaths = Utils.NoNull( - Utils.NoEmpty( - foundImage.path?.split(";")?.map((part) => { - if (part.startsWith("http")) { - return part - } - return part.split(":")[0] - }) - ) - ) + const allPaths = Lists.noNull(Lists.noEmpty(foundImage.path?.split(";")?.map((part) => { + if (part.startsWith("http")) { + return part + } + return part.split(":")[0] + }))) for (const path of allPaths) { cleanedImages.push({ path, diff --git a/src/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts b/src/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts index db6d92361..2ac4f9dce 100644 --- a/src/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts +++ b/src/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts @@ -1,10 +1,10 @@ import { ThemeConfigJson } from "../Json/ThemeConfigJson" -import { Utils } from "../../../Utils" import LineRenderingConfigJson from "../Json/LineRenderingConfigJson" import { LayerConfigJson } from "../Json/LayerConfigJson" import { DesugaringStep, Each, Fuse, On } from "./Conversion" import PointRenderingConfigJson from "../Json/PointRenderingConfigJson" import { ConversionContext } from "./ConversionContext" +import { Lists } from "../../../Utils/Lists" export class UpdateLegacyLayer extends DesugaringStep< LayerConfigJson | string | { builtin; override } @@ -190,7 +190,7 @@ export class UpdateLegacyLayer extends DesugaringStep< ) { iconConfig = iconConfig.render } - const icon = Utils.NoEmpty(iconConfig.split(";")) + const icon = Lists.noEmpty(iconConfig.split(";")) pr.marker = icon.map((i) => { if (i.startsWith("http")) { return { icon: i } @@ -281,7 +281,7 @@ class UpdateLegacyTheme extends DesugaringStep { } } - oldThemeConfig.layers = Utils.NoNull(oldThemeConfig.layers) + oldThemeConfig.layers = Lists.noNull(oldThemeConfig.layers) delete oldThemeConfig["language"] delete oldThemeConfig["version"] delete oldThemeConfig["clustering"] diff --git a/src/Models/ThemeConfig/Conversion/PrepareLayer.ts b/src/Models/ThemeConfig/Conversion/PrepareLayer.ts index 664a907ef..7489bd60e 100644 --- a/src/Models/ThemeConfig/Conversion/PrepareLayer.ts +++ b/src/Models/ThemeConfig/Conversion/PrepareLayer.ts @@ -1,18 +1,6 @@ -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" @@ -33,6 +21,7 @@ import { TagUtils } from "../../../Logic/Tags/TagUtils" import { ExpandFilter, PruneFilters } from "./ExpandFilter" import { ExpandTagRendering } from "./ExpandTagRendering" import layerconfig from "../../../assets/schemas/layerconfigmeta.json" +import { Lists } from "../../../Utils/Lists" class AddFiltersFromTagRenderings extends DesugaringStep { constructor() { @@ -360,7 +349,7 @@ export class AddEditingElements extends DesugaringStep { const addByDefault = this.builtinQuestions.filter((tr) => tr.labels?.indexOf(key) >= 0) const ids = new Set(addByDefault.map((tr) => tr.id)) const idsInOrder = this._desugaring.tagRenderingOrder?.filter((id) => ids.has(id)) ?? [] - return Utils.NoNull(idsInOrder.map((id) => this._desugaring.tagRenderings.get(id))) + return Lists.noNull(idsInOrder.map((id) => this._desugaring.tagRenderings.get(id))) } convert(json: LayerConfigJson, _: ConversionContext): LayerConfigJson { @@ -771,11 +760,11 @@ class ExpandIconBadges extends DesugaringStep { const condition = tr.condition for (const trElement of tr.mappings) { const showIf = TagUtils.optimzeJson({ - and: Utils.NoNull([ - condition, - { - or: Utils.NoNull([trElement.alsoShowIf, trElement.if]), - }, + and: Lists.noNull([ + condition, + { + or: Lists.noNull([trElement.alsoShowIf, trElement.if]), + }, ]), }) if (showIf === true) { @@ -984,14 +973,12 @@ export class AutoTitleIcon extends DesugaringStep { const allAutoIndex = json.titleIcons.indexOf("auto:*") if (allAutoIndex >= 0) { - const generated = Utils.NoNull( - json.tagRenderings.map((tr) => { - if (typeof tr === "string") { - return undefined - } - return this.createTitleIconsBasedOn(tr) - }) - ) + const generated = Lists.noNull(json.tagRenderings.map((tr) => { + if (typeof tr === "string") { + return undefined + } + return this.createTitleIconsBasedOn(tr) + })) json.titleIcons.splice(allAutoIndex, 1, ...generated) return json } @@ -1113,9 +1100,7 @@ export class OrderTagRendering extends DesugaringStep { - private static readonly layerAttributesOrder: ReadonlyArray = Utils.Dedup( - (layerconfig).filter((c) => c.path.length === 1).map((c) => c.path[0]) - ) + private static readonly layerAttributesOrder: ReadonlyArray = Lists.dedup((layerconfig).filter((c) => c.path.length === 1).map((c) => c.path[0])) constructor() { super("OrderLayer", "Reorders a tagRendering to the default order") @@ -1151,7 +1136,8 @@ export class PrepareLayer extends Fuse { "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("tagRenderings", new Concat(new ExpandRewrite()) + .andThenF(Utils.Flatten)), new On( "tagRenderings", (layer) => diff --git a/src/Models/ThemeConfig/Conversion/PrepareTheme.ts b/src/Models/ThemeConfig/Conversion/PrepareTheme.ts index 22becf17c..1a1f74ac3 100644 --- a/src/Models/ThemeConfig/Conversion/PrepareTheme.ts +++ b/src/Models/ThemeConfig/Conversion/PrepareTheme.ts @@ -1,14 +1,4 @@ -import { - Concat, - Conversion, - DesugaringContext, - DesugaringStep, - Each, - Fuse, - On, - Pass, - SetDefault, -} from "./Conversion" +import { Concat, Conversion, DesugaringContext, DesugaringStep, Each, Fuse, On, Pass, SetDefault } from "./Conversion" import { ThemeConfigJson } from "../Json/ThemeConfigJson" import { OrderLayer, PrepareLayer, RewriteSpecial } from "./PrepareLayer" import { LayerConfigJson } from "../Json/LayerConfigJson" @@ -22,6 +12,7 @@ import ValidationUtils from "./ValidationUtils" import { ConversionContext } from "./ConversionContext" import { ConfigMeta } from "../../../UI/Studio/configMeta" import themeconfig from "../../../assets/schemas/layoutconfigmeta.json" +import { Lists } from "../../../Utils/Lists" class SubstituteLayer extends Conversion { private readonly _state: DesugaringContext @@ -198,7 +189,7 @@ export class AddDefaultLayers extends DesugaringStep { convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson { const state = this._state - json.layers = Utils.NoNull([...(json.layers ?? [])]) + json.layers = Lists.noNull([...(json.layers ?? [])]) const alreadyLoaded = new Set(json.layers.map((l) => l["id"])) for (const layerName of Constants.added_by_default) { @@ -612,9 +603,7 @@ class PostvalidateTheme extends DesugaringStep { } } export class OrderTheme extends Fuse { - private static readonly themeAttributesOrder: ReadonlyArray = Utils.Dedup( - (themeconfig).filter((c) => c.path.length === 1).map((c) => c.path[0]) - ) + private static readonly themeAttributesOrder: ReadonlyArray = Lists.dedup((themeconfig).filter((c) => c.path.length === 1).map((c) => c.path[0])) constructor() { super("Reorders the layer to the default order", diff --git a/src/Models/ThemeConfig/Conversion/PrevalidateLayer.ts b/src/Models/ThemeConfig/Conversion/PrevalidateLayer.ts index a24fd8f51..e76d3019f 100644 --- a/src/Models/ThemeConfig/Conversion/PrevalidateLayer.ts +++ b/src/Models/ThemeConfig/Conversion/PrevalidateLayer.ts @@ -10,6 +10,7 @@ import { And } from "../../../Logic/Tags/And" import { DoesImageExist, ValidateFilter, ValidatePointRendering } from "./Validation" import { ValidateTagRenderings } from "./ValidateTagRenderings" import { TagsFilterClosed } from "../../../Logic/Tags/TagTypes" +import { Lists } from "../../../Utils/Lists" export class PrevalidateLayer extends DesugaringStep { private readonly _isBuiltin: boolean @@ -207,10 +208,8 @@ export class PrevalidateLayer extends DesugaringStep { } { // duplicate ids in tagrenderings check - const duplicates = Utils.NoNull( - Utils.Duplicates(Utils.NoNull((json.tagRenderings ?? []).map((tr) => tr["id"]))) - ) - if (duplicates.length > 0) { + const duplicates = Lists.noNull(Utils.Duplicates(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 context .enter("tagRenderings") diff --git a/src/Models/ThemeConfig/Conversion/ValidationUtils.ts b/src/Models/ThemeConfig/Conversion/ValidationUtils.ts index fe73b46b2..d6dddb92e 100644 --- a/src/Models/ThemeConfig/Conversion/ValidationUtils.ts +++ b/src/Models/ThemeConfig/Conversion/ValidationUtils.ts @@ -1,8 +1,8 @@ import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson" -import { Utils } from "../../../Utils" import SpecialVisualizations from "../../../UI/SpecialVisualizations" import { RenderingSpecification, SpecialVisualization } from "../../../UI/SpecialVisualization" import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson" +import { Lists } from "../../../Utils/Lists" export default class ValidationUtils { public static getAllSpecialVisualisations( @@ -51,9 +51,9 @@ export default class ValidationUtils { JSON.stringify(renderingConfig.mappings) ) } - const translations: any[] = Utils.NoNull([ - renderingConfig.render, - ...(renderingConfig.mappings ?? []).map((m) => m.then), + const translations: any[] = Lists.noNull([ + renderingConfig.render, + ...(renderingConfig.mappings ?? []).map((m) => m.then), ]) const all: RenderingSpecification[] = [] for (let translation of translations) { diff --git a/src/Models/ThemeConfig/FilterConfig.ts b/src/Models/ThemeConfig/FilterConfig.ts index ad6088bf7..6aa26adc7 100644 --- a/src/Models/ThemeConfig/FilterConfig.ts +++ b/src/Models/ThemeConfig/FilterConfig.ts @@ -10,6 +10,7 @@ import { Utils } from "../../Utils" import { RegexTag } from "../../Logic/Tags/RegexTag" import MarkdownUtils from "../../Utils/MarkdownUtils" import Validators, { ValidatorType } from "../../UI/InputElement/Validators" +import { Lists } from "../../Utils/Lists" export type FilterConfigOption = { question: Translation @@ -225,17 +226,17 @@ export default class FilterConfig { public GenerateDocs(): string { const hasField = this.options.some((opt) => opt.fields?.length > 0) return MarkdownUtils.table( - Utils.NoNull(["id", "question", "osmTags", hasField ? "fields" : undefined]), + Lists.noNull(["id", "question", "osmTags", hasField ? "fields" : undefined]), this.options.map((opt, i) => { const isDefault = this.options.length > 1 && (this.defaultSelection ?? 0) == i return ( - Utils.NoNull([ - this.id + "." + i, - isDefault ? `*${opt.question.txt}* (default)` : opt.question, - opt.osmTags?.asHumanString() ?? "", - opt.fields?.length > 0 - ? opt.fields.map((f) => f.name + " (" + f.type + ")").join(" ") - : undefined, + Lists.noNull([ + this.id + "." + i, + isDefault ? `*${opt.question.txt}* (default)` : opt.question, + opt.osmTags?.asHumanString() ?? "", + opt.fields?.length > 0 + ? opt.fields.map((f) => f.name + " (" + f.type + ")").join(" ") + : undefined, ]) ) }) diff --git a/src/Models/ThemeConfig/LayerConfig.ts b/src/Models/ThemeConfig/LayerConfig.ts index c4a1e4d58..97c86a1c3 100644 --- a/src/Models/ThemeConfig/LayerConfig.ts +++ b/src/Models/ThemeConfig/LayerConfig.ts @@ -23,6 +23,7 @@ import MarkdownUtils from "../../Utils/MarkdownUtils" import { And } from "../../Logic/Tags/And" import OsmWiki from "../../Logic/Osm/OsmWiki" import { UnitUtils } from "../UnitUtils" +import { Lists } from "../../Utils/Lists" export default class LayerConfig extends WithContextLoader { public static readonly syncSelectionAllowed = ["no", "local", "theme-only", "global"] as const @@ -226,7 +227,7 @@ export default class LayerConfig extends WithContextLoader { } if (json.lineRendering) { - this.lineRendering = Utils.NoNull(json.lineRendering).map( + this.lineRendering = Lists.noNull(json.lineRendering).map( (r, i) => new LineRenderingConfig(r, `${context}[${i}]`) ) } else { @@ -234,7 +235,7 @@ export default class LayerConfig extends WithContextLoader { } if (json.pointRendering) { - this.mapRendering = Utils.NoNull(json.pointRendering).map( + this.mapRendering = Lists.noNull(json.pointRendering).map( (r, i) => new PointRenderingConfig(r, `${context}[${i}](${this.id})`) ) } else { @@ -283,7 +284,7 @@ export default class LayerConfig extends WithContextLoader { } const missingIds = - Utils.NoNull(json.tagRenderings)?.filter( + Lists.noNull(json.tagRenderings)?.filter( (tr) => typeof tr !== "string" && tr["builtin"] === undefined && @@ -298,7 +299,7 @@ export default class LayerConfig extends WithContextLoader { throw msg } - this.tagRenderings = (Utils.NoNull(json.tagRenderings) ?? []).map( + this.tagRenderings = (Lists.noNull(json.tagRenderings) ?? []).map( (tr, i) => new TagRenderingConfig( tr, @@ -431,7 +432,7 @@ export default class LayerConfig extends WithContextLoader { return [ `[${tr.id}](#${tr.id}) ${origDef}`, - Utils.NoNull([q, r, options]).join("
"), + Lists.noNull([q, r, options]).join("
"), tr.labels.join(", "), key, ] @@ -560,7 +561,7 @@ export default class LayerConfig extends WithContextLoader { ] } - for (const revDep of Utils.Dedup(layerIsNeededBy?.get(this.id) ?? [])) { + for (const revDep of Lists.dedup(layerIsNeededBy?.get(this.id) ?? [])) { extraProps.push( ["This layer is needed as dependency for layer", `[${revDep}](#${revDep})`].join( " " @@ -568,32 +569,30 @@ export default class LayerConfig extends WithContextLoader { ) } - const tableRows: string[][] = Utils.NoNull( - this.tagRenderings - .map((tr) => tr.FreeformValues()) - .filter((values) => values !== undefined) - .filter((values) => values.key !== "id") - .map((values) => { - const embedded: string[] = values.values?.map((v) => - OsmWiki.constructLinkMd(values.key, v) - ) ?? ["_no preset options defined, or no values in them_"] - const statistics = `https://taghistory.raifer.tech/?#***/${encodeURIComponent( - values.key - )}/` - const tagInfo = `https://taginfo.openstreetmap.org/keys/${values.key}#values` - return [ - [ - ``, - ``, - OsmWiki.constructLinkMd(values.key), - ].join(" "), - values.type === undefined - ? "Multiple choice" - : `[${values.type}](../SpecialInputElements.md#${values.type})`, - embedded.join(" "), - ] - }) - ) + const tableRows: string[][] = Lists.noNull(this.tagRenderings + .map((tr) => tr.FreeformValues()) + .filter((values) => values !== undefined) + .filter((values) => values.key !== "id") + .map((values) => { + const embedded: string[] = values.values?.map((v) => + OsmWiki.constructLinkMd(values.key, v) + ) ?? ["_no preset options defined, or no values in them_"] + const statistics = `https://taghistory.raifer.tech/?#***/${encodeURIComponent( + values.key + )}/` + const tagInfo = `https://taginfo.openstreetmap.org/keys/${values.key}#values` + return [ + [ + ``, + ``, + OsmWiki.constructLinkMd(values.key), + ].join(" "), + values.type === undefined + ? "Multiple choice" + : `[${values.type}](../SpecialInputElements.md#${values.type})`, + embedded.join(" "), + ] + })) let quickOverview: string[] = [] if (tableRows.length > 0) { @@ -693,7 +692,7 @@ export default class LayerConfig extends WithContextLoader { } AllTagRenderings(): TagRenderingConfig[] { - return Utils.NoNull([...this.tagRenderings, ...this.titleIcons, this.title]) + return Lists.noNull([...this.tagRenderings, ...this.titleIcons, this.title]) } public isLeftRightSensitive(): boolean { diff --git a/src/Models/ThemeConfig/TagRenderingConfig.ts b/src/Models/ThemeConfig/TagRenderingConfig.ts index c3b807fe5..c4bbdb7f1 100644 --- a/src/Models/ThemeConfig/TagRenderingConfig.ts +++ b/src/Models/ThemeConfig/TagRenderingConfig.ts @@ -5,10 +5,7 @@ import { TagUtils } from "../../Logic/Tags/TagUtils" import { And } from "../../Logic/Tags/And" import { Utils } from "../../Utils" import { Tag } from "../../Logic/Tags/Tag" -import { - MappingConfigJson, - QuestionableTagRenderingConfigJson, -} from "./Json/QuestionableTagRenderingConfigJson" +import { MappingConfigJson, QuestionableTagRenderingConfigJson } from "./Json/QuestionableTagRenderingConfigJson" import Validators, { ValidatorType } from "../../UI/InputElement/Validators" import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson" import { RegexTag } from "../../Logic/Tags/RegexTag" @@ -21,6 +18,7 @@ import { UploadableTag } from "../../Logic/Tags/TagTypes" import LayerConfig from "./LayerConfig" import ComparingTag from "../../Logic/Tags/ComparingTag" import { Unit } from "../Unit" +import { Lists } from "../../Utils/Lists" export interface Mapping { readonly if: UploadableTag @@ -317,7 +315,7 @@ export default class TagRenderingConfig { } keys.push(...mapping.if.usedKeys()) } - keys = Utils.Dedup(keys) + keys = Lists.dedup(keys) for (let i = 0; i < this.mappings.length; i++) { const mapping = this.mappings[i] if (mapping.hideInAnswer) { @@ -352,7 +350,7 @@ export default class TagRenderingConfig { } allKeys = allKeys.concat(mapping.if.usedKeys()) } - allKeys = Utils.Dedup(allKeys) + allKeys = Lists.dedup(allKeys) if (allKeys.length > 1 && !allHaveIfNot) { throw `${context}: A multi-answer is defined, which generates values over multiple keys. Please define ifnot-tags too on every mapping` } @@ -541,20 +539,18 @@ export default class TagRenderingConfig { if?: TagsFilter then: TypedTranslation> img?: string - }[] = Utils.NoNull( - (this.mappings ?? [])?.filter((mapping) => { - if (mapping.if === undefined) { - return true - } - if (TagUtils.MatchesMultiAnswer(mapping.if, tags)) { - return true - } - if (mapping.alsoShowIf?.matchesProperties(tags)) { - return true - } - return false - }) - ) + }[] = Lists.noNull((this.mappings ?? [])?.filter((mapping) => { + if (mapping.if === undefined) { + return true + } + if (TagUtils.MatchesMultiAnswer(mapping.if, tags)) { + return true + } + if (mapping.alsoShowIf?.matchesProperties(tags)) { + return true + } + return false + })) if (freeformKeyDefined && tags[this.freeform.key] !== undefined) { const usedFreeformValues = new Set( @@ -659,9 +655,7 @@ export default class TagRenderingConfig { const key = this.freeform?.key const answerMappings = this.mappings?.filter((m) => m.hideInAnswer !== true) if (key === undefined) { - const values: { k: string; v: string }[][] = Utils.NoNull( - answerMappings?.map((m) => m.if.asChange({})) ?? [] - ) + const values: { k: string; v: string }[][] = Lists.noNull(answerMappings?.map((m) => m.if.asChange({})) ?? []) if (values.length === 0) { return } @@ -677,17 +671,13 @@ export default class TagRenderingConfig { } return { key: commonKey, - values: Utils.NoNull( - values.map((arr) => arr.filter((item) => item.k === commonKey)[0]?.v) - ), + values: Lists.noNull(values.map((arr) => arr.filter((item) => item.k === commonKey)[0]?.v)), } } - let values = Utils.NoNull( - answerMappings?.map( - (m) => m.if.asChange({}).filter((item) => item.k === key)[0]?.v - ) ?? [] - ) + let values = Lists.noNull(answerMappings?.map( + (m) => m.if.asChange({}).filter((item) => item.k === key)[0]?.v + ) ?? []) if (values.length === undefined) { values = undefined } @@ -1027,18 +1017,18 @@ export default class TagRenderingConfig { ].join(" ") } - return Utils.NoNull([ - "### " + this.id, - this.description, - this.question !== undefined - ? "The question is `" + this.question.txt + "`" - : "_This tagrendering has no question and is thus read-only_", - freeform, - mappings, - condition, - labels, - "", - reuse, + return Lists.noNull([ + "### " + this.id, + this.description, + this.question !== undefined + ? "The question is `" + this.question.txt + "`" + : "_This tagrendering has no question and is thus read-only_", + freeform, + mappings, + condition, + labels, + "", + reuse, ]).join("\n") } @@ -1061,7 +1051,7 @@ export default class TagRenderingConfig { tags.push(m.ifnot) } - return Utils.NoNull(tags) + return Lists.noNull(tags) } /** diff --git a/src/Models/ThemeConfig/ThemeConfig.ts b/src/Models/ThemeConfig/ThemeConfig.ts index a104f4f7c..d437fa3c3 100644 --- a/src/Models/ThemeConfig/ThemeConfig.ts +++ b/src/Models/ThemeConfig/ThemeConfig.ts @@ -13,6 +13,7 @@ import { TagsFilter } from "../../Logic/Tags/TagsFilter" import TagRenderingConfig from "./TagRenderingConfig" import { TagUtils } from "../../Logic/Tags/TagUtils" import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson" +import { Lists } from "../../Utils/Lists" /** * Minimal information about a theme @@ -381,7 +382,7 @@ export default class ThemeConfig implements ThemeInformation { const usedImages = jsonNoFavourites._usedImages usedImages.sort() - this.usedImages = Utils.Dedup(usedImages) + this.usedImages = Lists.dedup(usedImages) return this.usedImages } } diff --git a/src/UI/AllThemesGui.svelte b/src/UI/AllThemesGui.svelte index d5dd8a034..52b5d87fa 100644 --- a/src/UI/AllThemesGui.svelte +++ b/src/UI/AllThemesGui.svelte @@ -13,7 +13,6 @@ import ThemesList from "./BigComponents/ThemesList.svelte" import { MinimalThemeInformation } from "../Models/ThemeConfig/ThemeConfig" import LoginButton from "./Base/LoginButton.svelte" - import { Utils } from "../Utils" import Searchbar from "./Base/Searchbar.svelte" import ThemeSearch, { ThemeSearchIndex } from "../Logic/Search/ThemeSearch" import SearchUtils from "../Logic/Search/SearchUtils" @@ -26,6 +25,7 @@ import AccordionSingle from "./Flowbite/AccordionSingle.svelte" import MenuDrawerIndex from "./BigComponents/MenuDrawerIndex.svelte" import InsetSpacer from "./Base/InsetSpacer.svelte" + import { Lists } from "../Utils/Lists" AndroidPolyfill.init().then(() => console.log("Android polyfill setup completed")) const featureSwitches = new OsmConnectionFeatureSwitches() @@ -80,7 +80,7 @@ const customThemes: Store = Stores.listStabilized( state.installedUserThemes.stabilized(1000) - ).mapD((stableIds) => Utils.NoNullInplace(stableIds.map((id) => state.getUnofficialTheme(id)))) + ).mapD((stableIds) => Lists.noNullInplace(stableIds.map((id) => state.getUnofficialTheme(id)))) function filtered(themes: Store): Store { const searchIndex = Locale.language.map( diff --git a/src/UI/Base/ChartJsUtils.ts b/src/UI/Base/ChartJsUtils.ts index 6e6d856f5..1e578e73c 100644 --- a/src/UI/Base/ChartJsUtils.ts +++ b/src/UI/Base/ChartJsUtils.ts @@ -3,8 +3,7 @@ import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig" import { TagUtils } from "../../Logic/Tags/TagUtils" import { OsmFeature } from "../../Models/OsmFeature" import { Utils } from "../../Utils" -import { labels } from "wikibase-sdk/dist/src/helpers/simplify" -import { isInteger } from "tailwind-merge/dist/lib/validators" +import { Lists } from "../../Utils/Lists" class ChartJsColours { public static readonly unknownColor = "rgba(128, 128, 128, 0.2)" @@ -243,7 +242,7 @@ export class ChartJsUtils { if (options?.period === "month") { trimmedDays = trimmedDays.map((d) => d.substring(0, 7)) } - trimmedDays = Utils.Dedup(trimmedDays) + trimmedDays = Lists.dedup(trimmedDays) for (let i = 0; i < labels.length; i++) { const label = labels[i] diff --git a/src/UI/Base/Combine.ts b/src/UI/Base/Combine.ts index 5d9f80712..0adc2ec35 100644 --- a/src/UI/Base/Combine.ts +++ b/src/UI/Base/Combine.ts @@ -10,7 +10,7 @@ export default class Combine extends BaseUIElement { constructor(uiElements: (string | BaseUIElement)[]) { super() - this.uiElements = Utils.NoNull(uiElements).map((el) => { + this.uiElements = Utils.noNull(uiElements).map((el) => { if (typeof el === "string") { return new FixedUiElement(el) } diff --git a/src/UI/Base/Hotkeys.ts b/src/UI/Base/Hotkeys.ts index f2f601d57..c22f3377f 100644 --- a/src/UI/Base/Hotkeys.ts +++ b/src/UI/Base/Hotkeys.ts @@ -4,6 +4,7 @@ import { Translation } from "../i18n/Translation" import Translations from "../i18n/Translations" import MarkdownUtils from "../../Utils/MarkdownUtils" import Locale from "../i18n/Locale" +import { Lists } from "../../Utils/Lists" export default class Hotkeys { public static readonly _docs: UIEventSource< @@ -130,7 +131,7 @@ export default class Hotkeys { ] }) .sort() - byKey = Utils.NoNull(byKey) + byKey = Lists.noNull(byKey) for (let i = byKey.length - 1; i > 0; i--) { if (byKey[i - 1][0] === byKey[i][0]) { byKey.splice(i, 1) diff --git a/src/UI/Base/TableOfContents.ts b/src/UI/Base/TableOfContents.ts index ff6646c71..7035f2f4d 100644 --- a/src/UI/Base/TableOfContents.ts +++ b/src/UI/Base/TableOfContents.ts @@ -64,7 +64,7 @@ export default class TableOfContents { } } - const heading = Utils.Times(() => "#", firstTitle.depth) + const heading = Utils.times(() => "#", firstTitle.depth) toc = heading + " Table of contents\n\n" + toc const firstTitleIndex = md.indexOf(firstTitle.title) diff --git a/src/UI/BigComponents/CopyrightSingleIcon.svelte b/src/UI/BigComponents/CopyrightSingleIcon.svelte index 347211b6b..ab2a286fa 100644 --- a/src/UI/BigComponents/CopyrightSingleIcon.svelte +++ b/src/UI/BigComponents/CopyrightSingleIcon.svelte @@ -2,6 +2,7 @@ import type SmallLicense from "../../Models/smallLicense" import { Utils } from "../../Utils" import { twJoin } from "tailwind-merge" + import { Lists } from "../../Utils/Lists" export let iconPath: string export let license: SmallLicense @@ -10,7 +11,7 @@ } catch (e) { console.warn(e) } - let sources = Utils.NoNull(Utils.NoEmpty(license?.sources)) + let sources = Utils.noNull(Lists.noEmpty(license?.sources)) function sourceName(lnk: string) { try { diff --git a/src/UI/BigComponents/Histogram.svelte b/src/UI/BigComponents/Histogram.svelte index a6263b339..8bb6aefa8 100644 --- a/src/UI/BigComponents/Histogram.svelte +++ b/src/UI/BigComponents/Histogram.svelte @@ -3,6 +3,7 @@ import type { ChartConfiguration } from "chart.js" import ChartJs from "../Base/ChartJs.svelte" import { ChartJsUtils } from "../Base/ChartJsUtils" + import { Lists } from "../../Utils/Lists" export let values: Store let counts: Store> = values.map( @@ -11,7 +12,7 @@ return undefined } - values = Utils.NoNull(values) + values = Utils.noNull(values) const counts = new Map() for (const value of values) { const c = counts.get(value) ?? 0 @@ -23,7 +24,7 @@ let max: Store = counts.mapD(counts => Math.max(...Array.from(counts.values()))) let keys: Store = counts.mapD(counts => { - const keys = Utils.Dedup(counts.keys()) + const keys = Lists.dedup(counts.keys()) keys.sort(/*inplace sort*/) return keys }) diff --git a/src/UI/BigComponents/NewPointLocationInput.svelte b/src/UI/BigComponents/NewPointLocationInput.svelte index bbc60aea0..61407c7c3 100644 --- a/src/UI/BigComponents/NewPointLocationInput.svelte +++ b/src/UI/BigComponents/NewPointLocationInput.svelte @@ -13,12 +13,12 @@ import SnappingFeatureSource from "../../Logic/FeatureSource/Sources/SnappingFeatureSource" import FeatureSourceMerger from "../../Logic/FeatureSource/Sources/FeatureSourceMerger" import LayerConfig from "../../Models/ThemeConfig/LayerConfig" - import { Utils } from "../../Utils" import Move_arrows from "../../assets/svg/Move_arrows.svelte" import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource" import { Tag } from "../../Logic/Tags/Tag" import { TagUtils } from "../../Logic/Tags/TagUtils" import type { WayId } from "../../Models/OsmFeature" + import { Lists } from "../../Utils/Lists" /** * An advanced location input, which has support to: @@ -114,7 +114,7 @@ }) } const snappedLocation = new SnappingFeatureSource( - new FeatureSourceMerger(...Utils.NoNull(snapSources)), + new FeatureSourceMerger(...(Lists.noNull(snapSources))), // We snap to the (constantly updating) map location mapProperties.location, { diff --git a/src/UI/BigComponents/ShareScreen.svelte b/src/UI/BigComponents/ShareScreen.svelte index fe7280f51..e6a48377c 100644 --- a/src/UI/BigComponents/ShareScreen.svelte +++ b/src/UI/BigComponents/ShareScreen.svelte @@ -10,11 +10,11 @@ import { QueryParameters } from "../../Logic/Web/QueryParameters" import Tr from "../Base/Tr.svelte" import Translations from "../i18n/Translations" - import { Utils } from "../../Utils" import Qr from "../../Utils/Qr" import AccordionSingle from "../Flowbite/AccordionSingle.svelte" import Constants from "../../Models/Constants" import Copyable from "../Base/Copyable.svelte" + import { Lists } from "../../Utils/Lists" export let state: ThemeViewState const tr = Translations.t.general.sharescreen @@ -45,7 +45,7 @@ enableGeolocation: boolean ) { const layout = state.theme - let excluded = Utils.NoNull([ + let excluded = Lists.noNull([ showWelcomeMessage ? undefined : "fs-welcome-message", enableLogin ? undefined : "fs-enable-login", enableFilters ? undefined : "fs-filter", @@ -79,7 +79,7 @@ .filter((part) => !part.startsWith("layer-")) .concat(...layers) .concat(excluded.map((k) => k + "=" + false)) - linkToShare = baseLink + Utils.Dedup(params).join("&") + linkToShare = baseLink + Lists.dedup(params).join("&") if (layout.definitionRaw !== undefined) { linkToShare += "&userlayout=" + (layout.definedAtUrl ?? layout.id) diff --git a/src/UI/BigComponents/ThemesList.svelte b/src/UI/BigComponents/ThemesList.svelte index c95f51888..8684a9cb4 100644 --- a/src/UI/BigComponents/ThemesList.svelte +++ b/src/UI/BigComponents/ThemesList.svelte @@ -23,7 +23,7 @@ ? "flex flex-wrap items-center justify-center gap-x-2" : "theme-list my-2 gap-4 md:grid md:grid-flow-row md:grid-cols-2 lg:grid-cols-3"} > - {#each Utils.DedupOnId(Utils.NoNull(themes)) as theme (theme.id)} + {#each Utils.DedupOnId(Utils.noNull(themes)) as theme (theme.id)} {#if $search && hasSelection && themes?.[0] === theme}